如何在 .NET 6 中使用最少的 API 实现响应缓存?

kon*_*kri 2 c# caching response .net-6.0 minimal-apis

为了实现响应缓存,需要做的就是:

  • 注入.AddResponseCaching()到服务中,
  • 用 装饰控制器动作[ResponseCache(Duration = 10)]

现在我正在尝试 .NET 6 附带的最小 API,除了自己添加标头之外,我还没有找到其他方法cache-control: public,max-age=10

有更优雅的方法吗?

Gur*_*ron 7

ResponseCacheAttribute是 MVC 的一部分,根据文档将应用于:

  • Razor 页面:属性不能应用于处理程序方法。
  • MVC 控制器。
  • MVC 操作方法:方法级属性覆盖类级属性中指定的设置。

所以看来自己添加缓存头是唯一的选择。如果您愿意,可以使用自定义中间件对其进行一些“美化”。沿着这样的思路:

class CacheResponseMetadata
{
// add configuration properties if needed
}

class AddCacheHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public AddCacheHeadersMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        if (httpContext.GetEndpoint()?.Metadata.GetMetadata<CacheResponseMetadata>() is { } mutateResponseMetadata)
        {
            if (httpContext.Response.HasStarted)
            {
                throw new InvalidOperationException("Can't mutate response after headers have been sent to client.");
            }
            httpContext.Response.Headers.CacheControl = new[] { "public", "max-age=100" };
        }
        await _next(httpContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

及用法:

app.UseMiddleware<AddCacheHeadersMiddleware>(); // optionally move to extension method 
app.MapGet("/cache", () => $"Hello World, {Guid.NewGuid()}!")
    .WithMetadata(new CacheResponseMetadata()); // optionally move to extension method
Run Code Online (Sandbox Code Playgroud)

.NET 7 更新

对于 .NET 7,您可以配置输出缓存(有关响应缓存的差异,请参阅链接的文章):

输出缓存中间件可用于所有类型的 ASP.NET Core 应用程序:Minimal API、带控制器的 Web API、MVC 和 Razor Pages。

可以通过或方法调用为每个端点完成输出缓存:OutputCacheAttributeCacheOutput

app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) => Gravatar.WriteGravatar(context));
Run Code Online (Sandbox Code Playgroud)

或者通过策略对于多个端点

以下代码为应用程序的所有端点配置缓存,过期时间为 10 秒。

builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromSeconds(10)));
});
Run Code Online (Sandbox Code Playgroud)