MVC5:控制器中的属性路由优先级

时间:2014-02-16 09:38:49

标签: asp.net-mvc-routing asp.net-mvc-5 attributerouting

我在控制器中使用MVC5的属性路由。

问题:

有没有办法控制控制器之间的属性路由优先级?

考虑以下

[Route("home/{action=index}/{username?}")]
public class HomeController : Controller
{
    [Route("home/index/{username?}", Order = 1)]
    [Route("home/{username?}", Order = 2)]
    [Route("{username?}", Order = 3)]
    public ActionResult Index()
    {
        // ... bunch of stuff
    }
}

基于上面的代码,应使用以下请求调用HomeController.Index()操作方法:

  • 域/
  • domain / {username}
  • domain / home /
  • 域/家庭/ {用户名}
  • domain / home / index /
  • domain / home / index / {username}

第二个控制器:

[Authorize(Roles = "Member")]
[Route("profile/{action=index}")]
public class ProfileController : Controller
{
    [Route("profile")]
    public ActionResult Index()
    {

    }
}

应使用以下请求调用ProfileController.Index()

  • 域/个人资料
  • 域/简档/索引

问题

从示例中,如果我在网址中发送domain/profile,则会引发歧义异常。似乎domain/{username}domain/profile之间存在歧义。

现在,如果我使用基于约定的路由,这将有效(首次匹配获胜)。但它可以在MVC5属性路由中完成吗?因为我发现第三方库支持控制器之间的优先级

https://github.com/mccalltd/AttributeRouting/wiki/Controlling-Route-Precedence

routes.MapAttributeRoutes(config =>
{
    config.AddRoutesFromController<ProfileController>();
    config.AddRoutesFromController<HomeController>();
});

1 个答案:

答案 0 :(得分:1)

不,在ASP.Net MVC 5.2.3中不可能优先考虑控制器路由。如果多次匹配,则忽略操作的顺序并抛出异常。

我已经通过从https://aspnetwebstack.codeplex.com/SourceControl/latest下载源并检查函数GetControllerTypeFromDirectRoute(下面)来验证这一点。用这个函数做出的调用都没有做任何事情来确定路由的优先顺序,它们只是被找到并报告回来。如您所见,GetControllerTypeFromDirectRoute只会引发多重匹配。

一点都不好,但希望这能节省一些时间。

我将手动映射的路由放入以避免此问题。

 private static Type GetControllerTypeFromDirectRoute(RouteData routeData)
    {
        Contract.Assert(routeData != null);

        var matchingRouteDatas = routeData.GetDirectRouteMatches();

        List<Type> controllerTypes = new List<Type>();
        foreach (var directRouteData in matchingRouteDatas)
        {
            if (directRouteData != null)
            {
                Type controllerType = directRouteData.GetTargetControllerType();
                if (controllerType == null)
                {
                    // We don't expect this to happen, but it could happen if some code messes with the 
                    // route data tokens and removes the key we're looking for. 
                    throw new InvalidOperationException(MvcResources.DirectRoute_MissingControllerType);
                }

                if (!controllerTypes.Contains(controllerType))
                {
                    controllerTypes.Add(controllerType);
                }
            }
        }

        // We only want to handle the case where all matched direct routes refer to the same controller.
        // Handling the multiple-controllers case would put attribute routing down a totally different
        // path than traditional routing.
        if (controllerTypes.Count == 0)
        {
            return null;
        }
        else if (controllerTypes.Count == 1)
        {
            return controllerTypes[0];
        }
        else
        {
            throw CreateDirectRouteAmbiguousControllerException(controllerTypes);
        }
    }