OutputCache: expose `OutputCacheStream ` for reading in `ServeResponseAsync(..)` so response tags can be built
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
## Background and Motivation
For outout caching its often useful to be able to create tags based on the response. This occurs where different requests all touch the same underlying data and the tag representing this underlying data cannot be constructed based on the request data. For example, say, requests for a same user details based on UserId, Identity and EmailAddress.
```
https://api.com/userdetailsbyid?userid=1234
https://api.com/userdetailsbyemail?emailaddress=ua@oa.com
https://api.com/userdetailsbyidentity?identityprovider=https://idp.com&subject=abc
```
At the moment the only way to build the tags for these queries is to use the request data. The problem is that any command handlers would need to look up these details, and evict all these tags separately
```c#
await _outputCacheStore.EvictByTagAsync("Tag_User_by_userid=...);
await _outputCacheStore.EvictByTagAsync("Tag_User_by_emailaddress=...);
await _outputCacheStore.EvictByTagAsync("Tag_User_by_identity=...);
etc
```
What I'd like to do is to add a tag for each request in a custom policy by using the response which in my example contains the userid
```c#
await _outputCacheStore.EvictByTagAsync(
"Tag_UserId_1234",
CancellationToken.None
);
```
The workaround is to use reflection in the `ServeResponseAsync(..)` to get the value of the `outputCacheContext.OutputCacheStream` then invoke the `GetCachedResponseBody()` in the internal `OutputCacheStream` before reading the response (my policy is a generic typed policy so it's easy to deserialise and add the tags to the tags collection:
```c#
if (_responseTags.Count != 0)
{
var responseBodyJson = await ExtractResponseBodyAsync(
context: context,
cancellationToken: cancellationToken
);
var view = JsonConvert.DeserializeObject(responseBodyJson);
if (view is not null)
{
foreach (var tag in _responseTags)
{
context.Tags.Add(tag.Compile().Invoke(view));
}
}
}
```
Then somehow write it back. Who knows what this breaks...
## Proposed API
Make the `OutputCacheStream` property public or provide a public method to `GetCachedResponseBody()` from the `OutputCacheContext` in the `ServeResponseAsync(...)` method.
## Usage Examples
```c#
public async ValueTask ServeResponseAsync(
OutputCacheContext context,
CancellationToken cancellationToken)
{
var responseBody= await context.GetCachedResponseBody();
//etc
}
```
Contributor guide
Assessment
This issue has not been assessed yet.