ASP.NET Core中带内容类型后缀的ETag生成方案咨询
ASP.NET Core Web API 生成自定义ETag并确定序列化格式化程序
一、确定当前使用的序列化格式化程序
在ASP.NET Core中,Web API会根据请求的Accept标头、服务配置的输出格式化器集合,自动选择合适的格式化器序列化返回的C#对象。你可以通过以下两种方式获取最终选中的格式化器:
1. 全局动作过滤器方式
创建自定义动作过滤器,在OnActionExecuted阶段提取返回结果并确定格式化器:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Formatters; public class ETagFilter : IAsyncActionFilter { private readonly IOutputFormatterSelector _formatterSelector; public ETagFilter(IOutputFormatterSelector formatterSelector) { _formatterSelector = formatterSelector; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var executedContext = await next(); // 仅处理返回ObjectResult的接口 if (executedContext.Result is ObjectResult objectResult && objectResult.Value != null) { var formatterContext = new OutputFormatterWriteContext( executedContext.HttpContext, (stream, encoding) => new StreamWriter(stream, encoding), objectResult.DeclaredType ?? objectResult.Value.GetType(), objectResult.Value); // 获取最终选中的格式化器 var selectedFormatter = _formatterSelector.SelectFormatter( formatterContext, objectResult.Formatters, objectResult.ContentTypes); // 根据格式化器确定内容类型后缀 string contentTypeSuffix = selectedFormatter switch { JsonOutputFormatter => "json", XmlSerializerOutputFormatter => "xml", _ => "unknown" }; // 生成符合要求的ETag(标准ETag需包裹双引号) var etagValue = $"\"{Guid.NewGuid()}_{contentTypeSuffix}\""; executedContext.HttpContext.Response.Headers.ETag = etagValue; } } }
2. 单个控制器动作内处理
如果仅需在特定接口中实现,可直接在动作内获取格式化器:
[HttpGet] public IActionResult GetSampleData() { var data = new { Id = 1, Title = "Sample Content" }; var objectResult = new ObjectResult(data); var formatterContext = new OutputFormatterWriteContext( HttpContext, (stream, encoding) => new StreamWriter(stream, encoding), typeof(object), data); var formatterSelector = HttpContext.RequestServices.GetRequiredService<IOutputFormatterSelector>(); var selectedFormatter = formatterSelector.SelectFormatter( formatterContext, objectResult.Formatters, objectResult.ContentTypes); string suffix = selectedFormatter is JsonOutputFormatter ? "json" : "unknown"; Response.Headers.ETag = $"\"{Guid.NewGuid()}_{suffix}\""; return objectResult; }
二、注册并启用过滤器
将过滤器注册到服务容器,可全局启用或针对特定控制器启用:
// Program.cs 全局注册 builder.Services.AddControllers(options => { options.Filters.Add<ETagFilter>(); }); // 或在单个控制器上标记启用 [ServiceFilter(typeof(ETagFilter))] public class DataController : ControllerBase { // 接口逻辑... }
若需依赖ETag做缓存验证,确保已配置响应缓存中间件:
builder.Services.AddResponseCaching(); app.UseResponseCaching();
三、与旧ASP.NET Framework实现的对比
旧ASP.NET Framework中通常通过ActionFilterAttribute获取ObjectContent的格式化器:
// 旧框架实现示例 public class ETagFilter : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Response.Content is ObjectContent objectContent) { string suffix = objectContent.Formatter is JsonMediaTypeFormatter ? "json" : "xml"; var etag = new EntityTagHeaderValue($"\"{Guid.NewGuid()}_{suffix}\""); actionExecutedContext.Response.Headers.ETag = etag; } } }
ASP.NET Core的等效逻辑核心差异:
- 用
IOutputFormatterSelector替代旧的ObjectContent.Formatter获取逻辑 - 通过
OutputFormatterWriteContext模拟格式化器选择流程 - 保持生成带内容类型后缀的ETag逻辑,确保内容类型变更时旧缓存自动失效
内容的提问来源于stack exchange,提问作者cooper_milton
相关产品推荐
相关产品推荐

