如何在请求抵达WebAPI控制器前统一处理SomeId字段?
问题背景
现有ASP.NET Core Api控制器代码如下:
[ApiController] [Route("v1/[controller]/[action]")] public class AccountController : Controller { private readonly IClient _client; public AccountController(IClient client) { _client = client; } [HttpPost] public async Task<IActionResult> SomeAction([FromBody] SomeRequestModel request) { if (_client.SomeId == null) return BadRequest("Something could not be resolved"); request.SomeId = _client.SomeId.Value; // Do further processing } }
对应的请求模型:
public class SomeRequestModel { public long SomeId; // other fields }
现状与需求:
- 存在约100个不同Action,对应100个独立请求模型
- 所有模型均包含
SomeId字段,但未继承统一基类,且因来自外部项目无法修改 - 需要统一实现逻辑:检查
_client.SomeId是否已解析,未解析则返回BadRequest;已解析则为请求模型的SomeId字段赋值 - 不想在每个Action中重复编写相同代码,曾考虑用
System.Web.Http.AuthorizeAttribute解析JSON修改值,但认为效率极低,寻求最优方案
最优解决方案:异步Action过滤器
使用ASP.NET Core原生的异步Action过滤器,在Action执行前统一完成检查与赋值逻辑,完全消除重复代码:
1. 实现自定义异步过滤器
public class SomeIdActionFilter : IAsyncActionFilter { private readonly IClient _client; public SomeIdActionFilter(IClient client) { _client = client; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 检查SomeId是否已解析 if (_client.SomeId == null) { context.Result = new BadRequestObjectResult("Something could not be resolved"); return; } // 遍历Action参数,为含SomeId字段的模型赋值 foreach (var parameter in context.ActionArguments.Values) { if (parameter == null) continue; var someIdField = parameter.GetType().GetField("SomeId", BindingFlags.Public | BindingFlags.Instance); if (someIdField != null && someIdField.FieldType == typeof(long)) { someIdField.SetValue(parameter, _client.SomeId.Value); } } // 继续执行原Action逻辑 await next(); } }
2. 注册过滤器
根据需求选择全局或局部注册方式:
全局注册(所有Api控制器生效)
在Program.cs中配置:
builder.Services.AddControllers(options => { options.Filters.Add<SomeIdActionFilter>(); });
局部注册(指定控制器/Action生效)
- 控制器级别:
[ApiController] [Route("v1/[controller]/[action]")] [ServiceFilter(typeof(SomeIdActionFilter))] public class AccountController : Controller { // 控制器代码 }
- Action级别:
[HttpPost] [ServiceFilter(typeof(SomeIdActionFilter))] public async Task<IActionResult> SomeAction([FromBody] SomeRequestModel request) { // 直接编写业务逻辑,无需重复检查赋值代码 }
方案优势
- 完全消除重复代码,统一维护逻辑
- 基于ASP.NET Core原生机制,性能远优于解析JSON的方式
- 反射仅针对
SomeId字段,性能开销可忽略 - 注册方式灵活,适配不同场景需求
内容的提问来源于stack exchange,提问作者ertucode
相关产品推荐
相关产品推荐

