您可以创建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后,路由行为为:
- HTTP 请求
GET https://localhost:5001/cust/123/values 将匹配 Get(int customerId) 方法。
- HTTP 请求
POST https://localhost:5001/cust/123/values/opq 将匹配 Post(int customerId) 方法
- 因为我们有意在
/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] 装饰路由中的参数。