Skip to content

Can't modify OutputCacheContext.Tags from IOutputCachePolicy.ServeResponseAsync #46243

@DanielStout5

Description

@DanielStout5

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Assigning tags in ServeResponseAsync doesn't work; the tags don't get attached to the entries, so retrieving or evicting them does nothing.

It makes sense to be able to add tags to the cache entry in ServeResponseAsync (in a custom IOutputCachePolicy).

Work might be done during the request which resolves the value to be used in the tag, which is why it can't be assigned in CacheRequestAsync before the request has actually executed.

I believe the source of the issue is this block in OutputCacheMiddleware:

// Hook up to listen to the response stream
ShimResponseStream(context);

try
{
    await _next(httpContext);

    // The next middleware might change the policy
    foreach (var policy in policies)
    {
        await policy.ServeResponseAsync(context, httpContext.RequestAborted);
    }

    // If there was no response body, check the response headers now. We can cache things like redirects.
    StartResponse(context);

    // Finalize the cache entry
    await FinalizeCacheBodyAsync(context);

ShimResponseStream triggers FinalizeCacheHeaders which creates a copy of the tags (ToArray()) before the request gets executed in await _next - then even though the policy's ServeResponseAsync is using the request data to modify the tags, they don't get persisted by the call to FinalizeCacheBodyAsync, which uses the copy of the tags made in ShimResponseStream.

For a fix, what about removing this line in FinalizeCacheHeaders: Tags = context.Tags.ToArray()

And adding this one in FinalizeCacheBodyAsync: context.CachedResponse.Tags = context.Tags.ToArray();

For now I'm working around it by using reflection to set the OutputCacheContext.CachedResponse.Tags array inside ServerResponseAsync - reflection being necessary because CachedResponse (both the property and the class OutputCacheEntry) are internal

Expected Behavior

Assigning tags in ServeResponseAsync should attach them to the stored cache entry.

Steps To Reproduce

Create an implementation of IOutputCachePolicy and add:

        public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation)
        {
            context.AllowCacheStorage = true;
            context.Tags.Add("MyTagHere");
            return ValueTask.CompletedTask;
        }

Exceptions (if any)

No response

.NET Version

7.0.101

Anything else?

ASP.NET Core 7.0.2
Visual Studio Professional 2022

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions