【问题标题】:Attribute routing with default root parameter in WebAPIWebAPI中具有默认根参数的属性路由
【发布时间】:2020-04-15 00:51:37
【问题描述】:

我有一个 API,其中所有方法都需要一个固定参数 {customer}:

/cust/{customerId}/purchases
/cust/{customerId}/invoices
/cust/{customerId}/whatever*

如何映射所有控制器以默认以可重用的方式接收此参数,例如:

endpoints.MapControllerRoute(name: "Default", pattern: "/cust/{customerId:int}/{controller}*"

我在启动时使用 .net core 3.0 和新的 .useEndpoints 方法。

【问题讨论】:

    标签: rest asp.net-core asp.net-mvc-routing asp.net-core-webapi


    【解决方案1】:

    您可以创建ControllerModelConvention 的实现来自定义属性路由行为。详情请见official docs

    例如,假设您想将属性路由约定(如/cust/{customerId:int}/[controller])与全局现有属性相结合,只需创建一个约定如下:

    public class FixedCustomIdControllerConvention : IControllerModelConvention
    {
        public void Apply(ControllerModel controller)
        {
            var customerRouteModel= new AttributeRouteModel(){
                Template="/cust/{customerId:int}",
            };
            var isApiController= controller.ControllerType.CustomAttributes.Select(c => c.AttributeType)
                .Any(a => a == typeof(ApiControllerAttribute));
            foreach (var selector in controller.Selectors)
            {
                if(!isApiController)
                {
                    var oldAttributeRouteModel=selector.AttributeRouteModel;
                    var newAttributeRouteModel= oldAttributeRouteModel;
                    if(oldAttributeRouteModel != null){
                        newAttributeRouteModel= AttributeRouteModel.CombineAttributeRouteModel(customerRouteModel, oldAttributeRouteModel);
                    }
                    selector.AttributeRouteModel=newAttributeRouteModel;
                } else{
                    // ApiController won't honor the by-convention route
                    // so I just replace the template
                    var oldTemplate = selector.AttributeRouteModel.Template;
                    if(! oldTemplate.StartsWith("/") ){
                        selector.AttributeRouteModel.Template= customerRouteModel.Template + "/" + oldTemplate;
                    }
                }
            }
        }
    }
    

    然后在Startup中注册:

    services.AddControllersWithViews(opts =>{
        opts.Conventions.Add(new FixedCustomIdControllerConvention());
    });
    

    演示

    假设我们有一个ValuesController:

    [Route("[controller]")]
    public class ValuesController : Controller
    {
    
        [HttpGet]
        public IActionResult Get(int customerId)
        {
            return Json(new {customerId});
        }
    
        [HttpPost("opq")]
        public IActionResult Post(int customerId)
        {
            return Json(new {customerId});
        }
    
        [HttpPost("/rst")]
        public IActionResult PostRst(int customerId)
        {
            return Json(new {customerId});
        }
    }
    

    注册上述FixedCustomIdControllerConvention后,路由行为为:

    1. HTTP 请求 GET https://localhost:5001/cust/123/values 将匹配 Get(int customerId) 方法。
    2. HTTP 请求 POST https://localhost:5001/cust/123/values/opq 将匹配 Post(int customerId) 方法
    3. 因为我们有意在/rst 中放置了一个斜杠,所以通过了全局约定。因此,POST https://localhost:5001/rst 将匹配 PostRst(int customerId) 方法(使用 customId=0)

    如果您使用带有 [ApiController] 注释的控制器:

    [ApiController]
    [Route("[controller]")]
    public class ApiValuesController : ControllerBase
    {
    
        [HttpGet]
        public IActionResult Get([FromRoute]int customerId)
        {
            return new JsonResult(new {customerId});
        }
    
        [HttpPost("opq")]
        public IActionResult Post([FromRoute]int customerId)
        {
            return new JsonResult(new {customerId});
        }
    
        [HttpPost("/apirst")]
        public IActionResult PostRst([FromRoute]int customerId)
        {
            return new JsonResult(new {customerId});
        }
    }
    

    您可能需要使用[FromRoute] 装饰路由中的参数。

    【讨论】:

      猜你喜欢
      • 2013-10-01
      • 2021-06-10
      • 1970-01-01
      • 2014-03-14
      • 1970-01-01
      • 2021-01-17
      • 2015-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多