The Tags Property in OutputCache attribute is not working when using custom policies.
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Describe the bug
Hey, I'm trying to implement OutputCache with MultiTenancy Support, So I had to create a custom policy for that, I also used tags so that I can evict cache by tags + tenant id, this is how I'm doing it:
Custom OutputCache policy, MultitenantCachePolicy:
```
public class MultitenantCachePolicy : IOutputCachePolicy
{
public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation)
{
var attemptOutputCaching = AttemptOutputCaching(context);
context.EnableOutputCaching = true;
context.AllowCacheLookup = attemptOutputCaching;
context.AllowCacheStorage = attemptOutputCaching;
context.AllowLocking = true;
context.CacheVaryByRules.QueryKeys = "*";
var tenantId = context.HttpContext.Items["tenantId"] as string ?? "";
HashSet newTags = [];
foreach (var tag in context.Tags)
{
newTags.Add($"tenant:{tenantId}:{tag}");
}
newTags.Add($"tenant:{tenantId}");
context.Tags.UnionWith(newTags);
return ValueTask.CompletedTask;
}
public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation)
{
var response = context.HttpContext.Response;
if (!StringValues.IsNullOrEmpty(response.Headers.SetCookie))
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
if (response.StatusCode != StatusCodes.Status200OK)
{
context.AllowCacheStorage = false;
return ValueTask.CompletedTask;
}
return ValueTask.CompletedTask;
}
public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation)
=> ValueTask.CompletedTask;
private static bool AttemptOutputCaching(OutputCacheContext context)
{
var request = context.HttpContext.Request;
if (!HttpMethods.IsGet(request.Method) && !HttpMethods.IsHead(request.Method))
{
return false;
}
return true;
}
}
```
And this is how I register it:
```
services.AddOutputCache(options =>
{
options.AddPolicy(CacheConfig.CachePolicies.MultiTenantCache, o =>
{
o.Expire(TimeSpan.FromMinutes(10))
.VaryByValue(context => CacheExtension.VaryByTenantId(context))
.AddPolicy();
});
}
```
And this is how I use it in controller endpoints:
`[OutputCache(PolicyName = CacheConfig.CachePolicies.MultiTenantCache, Tags = [CacheConfig.CacheTags.DummyTag])]`
The problem is that the `DummyTag`is not getting used at all, when i set a breakpoint in `CacheRequestAsync`the context Tags list is empty, however, if i set the Tag using this way:
```
options.AddPolicy(CacheConfig.CachePolicies.MultiTenantCache, o =>
{
o.Expire(TimeSpan.FromMinutes(10))
.VaryByValue(context => CacheExtension.VaryByTenantId(context))
.AddPolicy()
.Tag(CacheConfig.CacheTags.DummyTag);
});
```
It works this way, what am I doing wrong here?
### Expected Behavior
I should be able to register one custom policy, however, when I use that policy in the OutputCache attribute, I should be able to use the `Tags` property so that each controller endpoint has its Tag while sharing the same policy.
### Steps To Reproduce
_No response_
### Exceptions (if any)
_No response_
### .NET Version
8.0.403
### Anything else?
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.