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

如何在ASP.NET Core Web API中为现有控制器动作路由附加自定义中间件?

如何将自定义中间件附加到已有的ASP.NET Core控制器动作路由

你遇到的问题其实很典型:用Map()手动创建的路由和控制器自带的路由是完全独立的端点条目,当请求/weatherforecast时,ASP.NET Core的路由系统会优先匹配控制器注册的端点,而不是你手动Map的那个,所以你的中间件根本没被执行到。

下面给你几个不用硬编码if判断的可行方案,按灵活性排序:

方案1:用自定义特性+条件中间件(最推荐)

这个方法通过给目标动作标记特性,让中间件自动识别并应用,完全不需要硬编码路由路径:

步骤1:定义一个标记特性

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ApplyCustomMiddlewareAttribute : Attribute, IEndpointMetadata
{
    // 空特性,仅用于标记元数据
}

步骤2:给控制器动作添加标记

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    // 给这个动作标记需要应用中间件
    [ApplyCustomMiddleware]
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        // 原动作逻辑
    }
}

步骤3:在Configure中添加条件中间件

用UseWhen()方法,检查请求匹配的端点是否带有我们的标记特性,再应用中间件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...其他前置中间件(比如异常处理、静态文件)

    // 针对带有标记特性的端点应用自定义中间件
    app.UseWhen(context =>
    {
        var endpoint = context.GetEndpoint();
        // 判断当前端点是否有我们的标记特性
        return endpoint?.Metadata.Any(m => m is ApplyCustomMiddlewareAttribute) == true;
    }, appBuilder =>
    {
        appBuilder.UseMiddleware<MyMiddleware>();
        appBuilder.UseMiddleware<VersionMiddleware>();
    });

    app.UseRouting();

    // ...其他中间件(比如授权)

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers(); // 正常注册控制器路由
    });
}

这个方案的优势是灵活可控:你可以给单个动作、整个控制器甚至全局添加标记,后续修改路由也不用同步调整中间件配置。

方案2:基于请求路径的管道分支

如果你的路由路径是固定的,可以用MapWhen()直接匹配路径,然后在分支管道里应用中间件,再继续执行控制器逻辑:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...其他中间件

    // 匹配/weatherforecast路径的请求,进入这个分支管道
    app.MapWhen(context => context.Request.Path.StartsWithSegments("/weatherforecast"), appBuilder =>
    {
        // 应用自定义中间件
        appBuilder.UseMiddleware<MyMiddleware>();
        appBuilder.UseMiddleware<VersionMiddleware>();
        
        // 必须重新添加路由和端点注册,让请求能走到控制器
        appBuilder.UseRouting();
        appBuilder.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    });

    // 处理其他路径的请求
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

这个方案适合路由固定的场景,但如果后续路由修改,你需要同步更新这里的路径判断。

方案3:直接修改控制器端点的请求管道

你可以在注册控制器路由时,通过端点约定直接给特定动作的管道插入中间件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...其他中间件

    app.UseRouting();

    // ...其他中间件

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers()
                 .Add(endpointBuilder =>
                 {
                     // 获取当前端点的控制器动作元数据
                     var actionDescriptor = endpointBuilder.Metadata.GetMetadata<ControllerActionDescriptor>();
                     if (actionDescriptor != null 
                         && actionDescriptor.ControllerName == "WeatherForecast" 
                         && actionDescriptor.ActionName == "Get")
                     {
                         // 创建包含自定义中间件的管道
                         var appBuilder = endpoints.CreateApplicationBuilder();
                         appBuilder.UseMiddleware<MyMiddleware>();
                         appBuilder.UseMiddleware<VersionMiddleware>();
                         
                         // 把原控制器动作的请求委托和新中间件合并
                         var originalDelegate = endpointBuilder.RequestDelegate;
                         endpointBuilder.RequestDelegate = appBuilder.Build().Use(originalDelegate).Invoke;
                     }
                 });
    });
}

这个方案直接修改了控制器端点的内部管道,不需要额外的分支,但需要硬编码控制器和动作名称,灵活性稍差。

为什么你之前的方法没生效?

endpoints.Map("/weatherforecast", ...)是新建了一个独立的端点,而控制器的/weatherforecast是由MapControllers()注册的另一个端点。当请求过来时,路由系统会匹配到控制器的端点(因为它的元数据更明确,属于控制器路由范畴),所以你新建的端点根本不会被命中,中间件自然不会执行。


内容的提问来源于stack exchange,提问作者Royi Namir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:17:44