Skip to content

Improve OutputCaching vary-by API #43355

@sebastienros

Description

@sebastienros

Background and Motivation

StringValues VaryByPrefix can contain multiple values which are not ordered deterministically. I suggest to change it to string VaryByKeyPrefix like in Response Caching, which will make its purpose obvious.

VaryByValue() supports "single" values and key/pair values. I suggest to only have key/pair values and have users always set a key to be able to order the values in the cache key.

Proposed API

namespace Microsoft.AspNetCore.OutputCaching;

public sealed class OutputCachePolicyBuilder
{
    public OutputCachePolicyBuilder();
    public OutputCachePolicyBuilder AddPolicy(Type policyType);
    public OutputCachePolicyBuilder AddPolicy<T>() where T : IOutputCachePolicy;
    public OutputCachePolicyBuilder With(Func<OutputCacheContext, bool> predicate);
    public OutputCachePolicyBuilder With(Func<OutputCacheContext, CancellationToken, ValueTask<bool>> predicate);
    public OutputCachePolicyBuilder Tag(params string[] tags);
    public OutputCachePolicyBuilder Expire(TimeSpan expiration);
    public OutputCachePolicyBuilder Cache();
    public OutputCachePolicyBuilder AllowLocking(bool lockResponse = true);
    public OutputCachePolicyBuilder Clear();
    public OutputCachePolicyBuilder NoCache();
    public OutputCachePolicyBuilder VaryByRouteValue(params string[] routeValueNames);
    public OutputCachePolicyBuilder VaryByQuery(params string[] queryKeys);
    public OutputCachePolicyBuilder VaryByHeader(params string[] headerNames);
-   public OutputCachePolicyBuilder VaryByValue(Func<HttpContext, string> varyBy);
-   public OutputCachePolicyBuilder VaryByValue(Func<HttpContext, CancellationToken, ValueTask<string>> varyBy);
+   public OutputCachePolicyBuilder VaryByValue(string key, string value);
    public OutputCachePolicyBuilder VaryByValue(Func<HttpContext, KeyValuePair<string, string>> varyBy);
    public OutputCachePolicyBuilder VaryByValue(Func<HttpContext, CancellationToken, ValueTask<KeyValuePair<string, string>>> varyBy);
+   public OutputCachePolicyBuilder VaryByKeyPrefix(string keyPrefix);
+   public OutputCachePolicyBuilder VaryByKeyPrefix(Func<HttpContext, string> keyPrefix);
+   public OutputCachePolicyBuilder VaryByKeyPrefix(Func<HttpContext, CancellationToken, ValueTask<string>> keyPrefix);
}
 
public sealed class CacheVaryByRules
{
    public CacheVaryByRules();
    public IDictionary<string, string> VaryByCustom { get; set }
    public StringValues RouteValueNames { get; set; }
    public StringValues HeaderNames { get; set; }
    public StringValues QueryKeys { get; set; }
-   public StringValues VaryByPrefix { get; set; }
+   public string? VaryByKeyPrefix { get; set; }
}

Usage Examples

options.AddBasePolicy(b => b.VaryByKeyPrefix(tenantId));
app.MapGet("/", endpoint.OutputCachebuilder.VaryByValue(c => "customerId", c.GetCurrentCustomerId());

-->

Alternative Designs

If having a prefix is only helpful for diagnostics (seeing groups of keys in the cache) then we could remove VaryByKeyPrefix and only use VaryByValues(string, string).

Risks

n/a

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions