You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:00:11