dotnet / dotnet/aspnetcore

Can't modify OutputCacheContext.Tags from IOutputCachePolicy.ServeResponseAsync

Open
#46,243 4 comments 8 reactions 0 assignees View on GitHub
area-middleware area-networking
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 5h
Merged PRs (30d)
276

Description

### Is there an existing issue for this?

- [X] 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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.