You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何从config.json为ASP.NET Core控制器所有Action设置路由前缀?

问题分析与解决方案

你的问题出在混用了特性路由和传统路由体系,这两套机制在ASP.NET Core中是独立运行的,不会自动合并,所以你用routes.MapRoute配置的传统路由前缀无法和控制器/Action上的[Route]特性路径结合,导致最终路由丢失了前缀。

下面给你两种可行的解决方案,推荐第二种,更符合特性路由的使用习惯:

方案一:使用全局路由前缀约定(推荐)

这种方法可以给所有带有[Route]特性的控制器统一添加来自配置的前缀,步骤如下:

1. 在config.json中添加前缀配置

{
  "ApiSettings": {
    "ControllerPrefix": "api/version/v1"
  }
}

2. 实现自定义路由约定类

创建一个实现IControllerModelConvention的类,用来给控制器路由添加全局前缀:

public class RoutePrefixConvention : IControllerModelConvention
{
    private readonly AttributeRouteModel _globalPrefix;

    public RoutePrefixConvention(string prefix)
    {
        _globalPrefix = new AttributeRouteModel(new RouteAttribute(prefix));
    }

    public void Apply(ControllerModel controller)
    {
        // 遍历控制器的所有路由选择器,合并全局前缀
        foreach (var selector in controller.Selectors)
        {
            if (selector.AttributeRouteModel != null)
            {
                // 合并全局前缀和控制器/Action的路由
                selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                    _globalPrefix, selector.AttributeRouteModel);
            }
            else
            {
                // 如果控制器没有设置[Route]特性,直接使用全局前缀
                selector.AttributeRouteModel = _globalPrefix;
            }
        }
    }
}

3. 在Startup.cs中注册约定并绑定配置

ConfigureServices方法里,读取配置并添加自定义约定:

public void ConfigureServices(IServiceCollection services)
{
    // 读取配置中的API前缀
    var apiPrefix = Configuration.GetValue<string>("ApiSettings:ControllerPrefix");
    
    services.AddControllers(options =>
    {
        // 添加全局路由前缀约定
        options.Conventions.Add(new RoutePrefixConvention(apiPrefix));
    });
}

4. 简化控制器的Route特性配置

现在你的控制器可以去掉原来的固定前缀[Route],Action直接保留自己的路由特性即可:

// 控制器不需要再写固定前缀的[Route]特性
public class MyController : ControllerBase 
{
    [Route("receipts/verifyReceipt")]
    public IActionResult VerifyReceipt(...){....}
    // 其他Action的Route特性保持不变
}

这样生成的路由就是你想要的api/version/v1/receipts/verifyReceipt

方案二:针对单个控制器绑定配置前缀

如果你只想给特定控制器添加配置的前缀,而不是全局所有控制器,可以这样做:

1. 同样先在config.json中添加配置(同方案一)

2. 在Startup.cs中绑定配置类

先创建配置类:

public class ApiSettings
{
    public string ControllerPrefix { get; set; }
}

然后在ConfigureServices中绑定:

services.Configure<ApiSettings>(Configuration.GetSection("ApiSettings"));

3. 使用约定给单个控制器添加前缀

ConfigureServices中,针对特定控制器添加前缀:

services.AddControllers(options =>
{
    var apiPrefix = Configuration.GetValue<string>("ApiSettings:ControllerPrefix");
    // 只给MyController添加前缀
    options.Conventions.Add(new RoutePrefixConvention(apiPrefix)
        .ForController<MyController>());
});

(注:如果你的RoutePrefixConvention没有ForController方法,可以扩展一下,或者直接在Apply方法里判断控制器类型)


为什么你原来的配置无效?

你用routes.MapRoute配置的是传统路由,而控制器上的[Route]属于特性路由,ASP.NET Core会优先使用特性路由,忽略传统路由的配置。当你给控制器设置[Route("", Name = "default")]时,相当于控制器没有路由前缀,所以Action的路由就直接是/receipts/verifyReceipt,自然丢失了前缀。

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

火山引擎 最新活动