如何在ASP.NET Core Web API中优雅提取请求HTTP头并存储到控制器属性?
更优雅的实现方案
不用自定义基类也能搞定这个需求,以下是几个更灵活的实现方式:
方案1:自定义Action过滤器+接口约定
通过接口约定替代基类继承,解耦控制器与头信息提取逻辑:
- 定义一个接口,约定头信息的存储属性:
public interface IHeaderHolder { string TargetHeader { get; set; } }
- 让需要获取头信息的控制器实现该接口:
[ApiController] [Route("api/[controller]")] public class DemoController : ControllerBase, IHeaderHolder { public string TargetHeader { get; set; } [HttpGet] public IActionResult Get() { return Ok(TargetHeader); } }
- 编写Action过滤器,在Action执行前提取头信息并赋值:
public class ExtractHeaderFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // 判断控制器是否实现了约定接口,是则赋值 if (context.Controller is IHeaderHolder headerHolder) { headerHolder.TargetHeader = context.HttpContext.Request.Headers["X-Target-Header"].FirstOrDefault(); } } public void OnActionExecuted(ActionExecutedContext context) { // 无需后置操作可留空 } }
- 注册过滤器,可全局生效或仅针对特定控制器/Action:
// 全局注册(Program.cs) builder.Services.AddControllers(options => { options.Filters.Add<ExtractHeaderFilter>(); }); // 单个控制器/Action注册,需先将过滤器注册为服务 builder.Services.AddScoped<ExtractHeaderFilter>(); // 控制器上标记:[ServiceFilter(typeof(ExtractHeaderFilter))]
方案2:用IHttpContextAccessor直接获取
无需过滤器,直接在控制器中注入IHttpContextAccessor,封装成懒加载属性:
- 先注册服务(Program.cs):
builder.Services.AddHttpContextAccessor();
- 在控制器中使用:
[ApiController] [Route("api/[controller]")] public class DemoController : ControllerBase { private readonly IHttpContextAccessor _httpContextAccessor; private string _targetHeader; // 懒加载提取头信息,第一次访问时自动获取 public string TargetHeader { get { if (_targetHeader == null) { _targetHeader = _httpContextAccessor.HttpContext.Request.Headers["X-Target-Header"].FirstOrDefault(); } return _targetHeader; } } public DemoController(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } [HttpGet] public IActionResult Get() { return Ok(TargetHeader); } }
方案3:.NET 6+ 端点过滤器(Endpoint Filter)
如果用的是.NET 6及以上版本,可使用更轻量的端点过滤器:
- 编写端点过滤器:
public class ExtractHeaderEndpointFilter : IEndpointFilter { public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) { // 获取控制器实例并判断是否实现约定接口 if (context.HttpContext.GetEndpoint()?.Metadata.GetMetadata<ControllerActionDescriptor>() is { } descriptor && context.Arguments.FirstOrDefault(a => descriptor.ControllerTypeInfo.IsAssignableFrom(a.GetType())) is IHeaderHolder headerHolder) { headerHolder.TargetHeader = context.HttpContext.Request.Headers["X-Target-Header"].FirstOrDefault(); } return await next(context); } }
- 注册方式同Action过滤器,也可直接在Action上标记:
[HttpGet] [EndpointFilter<ExtractHeaderEndpointFilter>] public IActionResult Get() { return Ok(TargetHeader); }
内容的提问来源于stack exchange,提问作者tlt
相关产品推荐
相关产品推荐

