我目前正在实现 .NET 7 框架的一些新功能。其中一部分与新的缓存机制有关。
启动时我已经配置了缓存:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
builder.Services.AddCors();
builder.Services.AddOutputCache();
//builder.Services.InitializeApplication(builder.Configuration);
var app = builder.Build();
app.UseOutputCache();
app.UseCors();
//app.UseAuthentication();
//app.UseAuthorization();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGroup("reports-api/requests")
.MapRequestsApi();
app.MapHealthChecks("/healthcheck");
app.Run();
路由组如下所示:
public static class RequestsEndpoint
{
public static RouteGroupBuilder MapRequestsApi(this RouteGroupBuilder group)
{
group.MapGet("/all", async (IMediator mediator) =>
{
await Task.Delay(2000);
return await mediator.Send(new RetrieveRequestsQuery());
})
.CacheOutput(x => x.Tag("requests"));
group.MapPost("/add", async (string details, IMediator mediator, IOutputCacheStore store) =>
{
await mediator.Send(new AddRequestCommand { Details = details });
await store.EvictByTagAsync("requests", CancellationToken.None);
});
group.MapGet("/{id}", async (Guid requestId, IMediator mediator) =>
{
await mediator.Send(new RetrieveRequestDetailsQuery()
{
Id = requestId
});
});
//group.MapPut("/{id}", UpdateRequest);
//group.MapDelete("/{id}", DeleteRequest);
return group;
}
}
当我想从缓存中提供请求列表或当我想逐出缓存(列表中的新项目)时,带有标签的缓存机制可以正常工作
但是,我希望每个项目都有某种缓存 - 当我根据 ID 检索请求时,我只想缓存这些值,直到通过 PUT 或 PATCH 更改详细信息为止。
我能做的就是注册 具有相同标签(“requests”)的 group.MapGet("/{id}") 端点。但是,如果有更新,我将被迫驱逐所有内容。这并不理想。
我正在观看此视频 ( Output Cache Microsoft ),他们正在查看名为 DefaultOutputCachePolicy 的内容
我只能在.NET 7中找到接口(interface):IOutputCachePolicy,它要求我实现以下方法:
public class ByIdCachePolicy : IOutputCachePolicy
{
public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation) => throw new NotImplementedException();
public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation) => throw new NotImplementedException();
public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation) => throw new NotImplementedException();
}
文档中没有关于如何实现这一点的线索,而且我找不到默认策略的代码。我们应该如何实现这个接口(interface)?
最佳答案
我设法通过解决方法实现了我想要的目标:
group.MapGet("/{id}", async (Guid requestId, IMediator mediator) =>
{
await Task.Delay(2000);
return await mediator.Send(new RetrieveRequestDetailsQuery
{
Id = requestId
});
})
.CacheOutput(cachePolicyBuilder => cachePolicyBuilder.With(context =>
{
if (context.HttpContext.Request.QueryString.Value != null)
{
var queryParams = HttpUtility.ParseQueryString(context.HttpContext.Request.QueryString.Value);
context.Tags.Add(queryParams["requestId"]!);
}
return true;
}));
group.MapPut("/{id}",
async (Guid id, IOutputCacheStore store, CancellationToken ct) =>
await store.EvictByTagAsync(id.ToString(), CT));
使用cachePolicyBuilder With方法,我可以访问缓存上下文,并可以查看查询字符串并添加自定义标记(按ID)。
但是,这并不简单,因为 With 函数允许您过滤缓存的请求。我在这里所做的始终是返回 true,但是还添加了自定义标签。
不理想,但它有效......
编辑
经过进一步研究后,我最终使用了以下策略:
public class ByIdCachePolicy : IOutputCachePolicy
{
public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation)
{
var idRoute = context.HttpContext.Request.RouteValues["id"];
if (idRoute == null)
{
return ValueTask.CompletedTask;
}
context.Tags.Add(idRoute.ToString()!);
return ValueTask.CompletedTask;
}
public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation)=> ValueTask.CompletedTask;
public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation) => ValueTask.CompletedTask;
}
像这样:
group.MapGet("/{id}", async (Guid id, IMediator mediator) =>
{
await Task.Delay(2000);
return await mediator.Send(new RetrieveRequestDetailsQuery
{
Id = id
});
}).CacheOutput(x => x.AddPolicy<ByIdCachePolicy>());
关于c# - .NET 7 创建自定义输出缓存策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74610528/