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

本文关键字:路由 顺序 属性 是否 | 更新日期: 2023-09-27 18:17:50

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

这是我在区域注册文件中的路线:

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文件中定义,而不是用[Route()]件装饰它们。

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

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

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

您可以在此处查看示例和原始路由工厂属性源以供参考

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

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

 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 类。

另一种方法是,您可以尝试在项目中查找工作"订单"。如果省略测试,则没有那么多出现,有些在 routeSomething 类中。

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