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

时间:2015-10-15 17:50:55

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

因此,我将区域从使用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'作为group参数传入。但正则表达式并不特别有助于URL的最终呈现方式。

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

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

2 个答案:

答案 0 :(得分:3)

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

public class OptionalsRouteAttribute : RouteFactoryAttribute
{
    private object _defaults;

    public OptionalsRouteAttribute(string template, object defaults)
        : base(template)
    {
        Defaults = defaults;
    }

    [...]
}

你可以看到sample here 以及original 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; }

}

然后在Controller中:

 [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");
    }

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

答案 1 :(得分:2)

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

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代码。