使用属性路由时是否可以更改路由表中的路由顺序?

所以,我正在将区域从使用AreaRegistration切换到使用属性路由。 我遇到的问题似乎是由路由加载到路由表中的顺序引起的。 我通过最后加载有问题的路由解决了AreaRegistration中的问题,这样只有当所有其他路由不匹配时才会匹配该路由。 使用属性路由,这似乎不可能。 我在创建路由时有Order参数,但这不会影响路由表的方式,除非非常狭窄。

这是我在AreaRegistration文件中的路由:

context.MapRoute( name: "ActionItems_home", url: "ActionItems/{group}/{statuses}/{overdueOnly}", defaults: new { controller = "Home", action = "Index", group = "All", statuses = "New,Open", overdueOnly = false }, namespaces: new string[] { "IssueTracker.Areas.ActionItems.Controllers" } ); 

现在,当我尝试将其切换到属性路由时,唯一接近工作的是:

 [Route("", Order = 4)] [Route("{group:regex(^(?!Item|DecisionLogs))?}", Order = 3)] [Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open?}", Order = 2)] [Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open}/{overdueOnly:bool=false?}", Order = 1)] 

请注意,我必须放入正则表达式,因为否则不会调用Item控制器 – 相反,我最终将字符串’Item’作为group参数传入。 但正则表达式并不特别有助于URL的最终呈现方式。

我希望在URL中抑制可选参数,除非它们是非默认值。 我已经尝试将参数指定为可选参数,默认值,以及可选参数和默认值。 他们似乎都没有真正做到这一点。

当前的解决方案至少会提供一个没有查询字符串的URL,但它们包含可选参数并使事情变得丑陋。 现在,我只是在AreaRegistration文件中定义了AreaRegistration路线,而没有用[Route()]碎片装饰它们。

您真正的问题是如何使用属性路由配置原始路由。 订单问题只是配置多个路由而不是一个路由的副作用。 要实现所需的配置,您可以创建自定义RouteAttribute并在内部执行任何操作。

 public class OptionalsRouteAttribute : RouteFactoryAttribute { private object _defaults; public OptionalsRouteAttribute(string template, object defaults) : base(template) { Defaults = defaults; } [...] } 

您可以在此处查看示例和原始的RouteFactoryAttribute源以供参考

我担心我现在没有时间自己提供实际的实施,但我希望这会引导你走向正确的方向。

更新我尝试了这个,以下非常简单的解决方案按预期工作。 我的属性实现特定于您使用group,status和overdueOnly参数提供的示例,但您应该能够创建涵盖所有情况的更通用的解决方案(您还需要添加命名空间)

  public class OptionalsRouteAttribute : RouteFactoryAttribute { public OptionalsRouteAttribute(string template, string group, string statuses, bool overdueOnly) : base(template) { var defaults = new RouteValueDictionary { {"group", @group}, {"statuses", statuses}, {"overdueOnly", overdueOnly} }; Defaults = defaults; } public override RouteValueDictionary Defaults { get; } } 

然后在控制器中:

  [OptionalsRoute("ActionItemsAttribute/{group}/{statuses}/{overdueOnly}", "All", "New,Open", false)] public ActionResult AttributeRouting(string group, string statuses, bool overdueOnly) { ViewBag.Message = $"Attribute Routing: Group [{@group}] - Statuses [{statuses}] - overdueOnly [{overdueOnly}]"; return View("Index"); } 

它与初始路由配置完全相同,但使用属性。

ASP.NET MVC是开源的,其设计方式是每个层都可以由您自己替换。 您可以下载源代码 ,查找有问题的部分并找出它是如何工作的。 如果需要,最后用自己的代码替换。

 git clone https://git01.codeplex.com/aspnetwebstack.git 

如果您下载此源代码,您将找到带有CreateRoute方法的System.Web.Mvc.RouteAttribute类。 我不确定,但它可能与您的问题有某种联系。

 RouteEntry IDirectRouteFactory.CreateRoute(DirectRouteFactoryContext context) { Contract.Assert(context != null); IDirectRouteBuilder builder = context.CreateBuilder(Template); Contract.Assert(builder != null); builder.Name = Name; builder.Order = Order; return builder.Build(); } 

在此界面上查找引用,您可以找到DefaultDirectRouteProvider类。

另一种方法是你可以尝试在项目中找到工作“订单”。 如果省略test,则没有那么多事件,有些是在routeSomething类中。

您可以在Visual Studio中取消选中“仅我的代码”并调试ASP.NET MVC代码。