![](/img/trans.png)
[英]How to specify route options to specific controllers in ASP.NET MVC 5
[英]How to apply a common route for multiple ASP.NET MVC controllers
我有一个共同的基础 controller 和几个继承的 controller 类,它们应用了类似的路由。 我想应用不同路线的公共部分并将其应用到基础 class。 以下是我的代码的最低限度:
using Microsoft.AspNetCore.Mvc;
public abstract class CommonController : Controller
{
// Some common code here
}
[Route("api/v1/BookLookup")]
public class BooksController : CommonController
{
public async Task<JsonResult> GetAsync([FromBody]Dto1 filterParameters)
{
return await GetApiData(filterParameters);
}
}
[Route("api/v1/MovieLookup")]
public class MoviesController : CommonController
{
public async Task<JsonResult> GetAsync([FromBody]Dto1 filterParameters)
{
return await GetApiData(filterParameters);
}
}
我想要以下内容:
using Microsoft.AspNetCore.Mvc;
[Route("api/v1/")] // or any other attribute?
public abstract class CommonController : Controller
{
// Some common code here
}
[Route("BookLookup")]
public class BooksController : CommonController
{
public async Task<JsonResult> GetAsync([FromBody]Dto1 filterParameters)
{
return await GetApiData(filterParameters);
}
}
[Route("MovieLookup")]
public class MoviesController : CommonController
{
public async Task<JsonResult> GetAsync([FromBody]Dto1 filterParameters)
{
return await GetApiData(filterParameters);
}
}
这可能吗?如果是,怎么做?
The project targets .NET Core 2.0 and the Controller
class in the above example is ASP.NET Core MVC controller class, not Web API controller.
默认情况下,内置RouteAttribute
不适用于 controller inheritance。 但是,为了实现您的目标,您可以创建自定义IControllerModelConvention以应用在启动时考虑 controller inheritance 的规则。
为了避免与默认的[RouteAttribute]
,我创建了一个自定义MyRoutePrefixAttribute
而不是使用默认的[RouteAttribute]
(如果您认为应该覆盖此行为,请随意使用[RouteAttribute]
):
[AttributeUsage(AttributeTargets.Class)]
public class MyRoutePrefixAttribute : Attribute
{
public MyRoutePrefixAttribute(string prefix) { Prefix = prefix; }
public string Prefix { get; }
}
为了从 inheritance 链中查找这个[MyRoutePrefixAttribute]
,我创建了一个RoutePrefixConvention
递归组合前缀:
public class RoutePrefixConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
foreach (var selector in controller.Selectors)
{
var prefixes = GetPrefixes(controller.ControllerType); // [prefix, parentPrefix, grandpaPrefix,...]
if(prefixes.Count == 0) continue;
// combine these prefixes one by one
var prefixRouteModels = prefixes.Select(p => new AttributeRouteModel(new RouteAttribute(p.Prefix)))
.Aggregate( (acc , prefix)=> AttributeRouteModel.CombineAttributeRouteModel(prefix, acc));
selector.AttributeRouteModel = selector.AttributeRouteModel != null ?
AttributeRouteModel.CombineAttributeRouteModel(prefixRouteModels, selector.AttributeRouteModel):
selector.AttributeRouteModel = prefixRouteModels;
}
}
private IList<MyRoutePrefixAttribute> GetPrefixes(Type controlerType)
{
var list = new List<MyRoutePrefixAttribute>();
FindPrefixesRec(controlerType, ref list);
list = list.Where(r => r!=null).ToList();
return list;
// find [MyRoutePrefixAttribute('...')] recursively
void FindPrefixesRec(Type type, ref List<MyRoutePrefixAttribute> results)
{
var prefix = type.GetCustomAttributes(false).OfType<MyRoutePrefixAttribute>().FirstOrDefault();
results.Add(prefix); // null is valid because it will seek prefix from parent recursively
var parentType = type.BaseType;
if(parentType == null) return;
FindPrefixesRec(parentType, ref results);
}
}
}
此约定不会影响性能:它仅在启动时通过 inheritance 链搜索所有[MyRoutePrefixAttribute]
属性。
最后,不要忘记在你的启动中添加这个约定:
services.AddMvc(opts =>
{
opts.Conventions.Add(new RoutePrefixConvention());
});
Controller:
[MyRoutePrefix("api/v1")]
public class CommonController : Controller
{
}
[Microsoft.AspNetCore.Mvc.Route("MovieLookup")]
public class MoviesController : CommonController
{
public string GetAsync()
{
return "MovieLookup";
}
}
测试结果:
希望这可以帮到你。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.