ASP.NET请求超时中间件:无需取消令牌如何终止端点任务
解决方案
1. 修正中间件顺序
你的中间件配置顺序错误,UseRequestTimeouts必须在UseEndpoints之前注册,否则超时逻辑无法作用于控制器端点。修改Configure方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ...其他中间件(如UseSession等) app.UseRequestTimeouts() .UseEndpoints(routes => { routes.MapControllers(); }); }
2. 自动注入CancellationToken到所有控制器方法
通过自定义IControllerModelProvider,可以自动为所有未显式声明CancellationToken参数的控制器Action添加该参数,并绑定到HttpContext.RequestAborted令牌,无需手动修改每个方法。
步骤1:实现自定义控制器模型提供器
public class AutoCancellationTokenProvider : IControllerModelProvider { public int Order => -1000; // 确保在默认提供器后执行 public void OnProvidersExecuting(ControllerModelProviderContext context) { } public void OnProvidersExecuted(ControllerModelProviderContext context) { foreach (var controller in context.Results) { foreach (var action in controller.Actions) { if (!action.Parameters.Any(p => p.ParameterType == typeof(CancellationToken))) { var param = new ControllerParameterModel { ParameterType = typeof(CancellationToken), Name = "cancellationToken", BindingInfo = new BindingInfo { BindingSource = BindingSource.Special, BinderModelName = "RequestAborted" } }; action.Parameters.Add(param); } } } } }
步骤2:注册提供器
在ConfigureServices中添加注册:
public void ConfigureServices(IServiceCollection services) { // ...其他服务配置 services.AddRequestTimeouts(options => options.DefaultPolicy = new RequestTimeoutPolicy { Timeout = TimeSpan.FromMilliseconds(_requestTimeoutMs) }); services.AddSingleton<IControllerModelProvider, AutoCancellationTokenProvider>(); }
3. 确保服务层方法支持取消
为了让超时能真正终止任务,你的_userService.GetAsync方法需要接受CancellationToken并传递到底层异步操作(如数据库查询、HTTP请求等):
// 服务层示例 public async Task<UserDto> GetAsync(Guid userId, CancellationToken cancellationToken) { // 传递令牌到异步操作,比如EF Core查询 return await _dbContext.Users .Where(u => u.Id == userId) .FirstOrDefaultAsync(cancellationToken); }
此时,控制器方法会自动接收注入的CancellationToken,只需在调用服务时传递:
[HttpGet(nameof(Get))] public async Task<UserDto> Get([FromQuery] Guid userId, CancellationToken cancellationToken) => await _userService.GetAsync(userId, cancellationToken);
(注:如果不想修改控制器方法签名,也可以直接通过ControllerBase.HttpContext.RequestAborted获取令牌并传递给服务方法)
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

