2015-10-15 50 views
14

因此,我正在使用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文件中&沒有用[Route()]件裝飾它們。

+0

看看http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#order –

+0

謝謝你,阿米爾。看起來,RouteOrder屬性可用於ApiController類...在特定版本的Web API控制器中。但是,它不適用於從'System.Web.Mvc.Controller'類繼承的控制器,這是我遇到問題的地方。因爲ApiController在MVC5中沒有RouteOrder參數(加上,這會打斷控制器),所以將控制器的繼承改爲'System.Web.Http.ApiController'也沒有幫助。 –

+0

聽起來像你可能不在ASP.NET MVC 5.我認爲屬性路由僅在5中引入。http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing- in-asp-net-mvc-5.aspx –

回答

3

你真正的問題是如何使用屬性路由配置你的原始路由。訂單問題只是配置多條路線而非一條路線的副作用。 要實現您所需的配置,您可以創建一個自定義RouteAttribute並執行您需要的任何內容。

public class OptionalsRouteAttribute : RouteFactoryAttribute 
{ 
    private object _defaults; 

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

    [...] 
} 

你可以看到一個sample hereoriginal RouteFactoryAttribute源供參考

恐怕我沒有時間,現在提供的實際實現我自己,但我希望這會導致你正確的方向。

UPDATE 我已經給了這個試試,下面非常簡單的解決方案按預期工作。我的屬性實現特定於您提供的組,狀態和過期僅限參數的示例,但您應該能夠創建涵蓋所有情況的更通用的解決方案(您還需要添加名稱空間)

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

而且它的工作原理完全一樣,你最初的路由配置,但使用的屬性。

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

另一種方法是,您可以嘗試在項目中找到「訂單」工作。如果你省略了測試,那麼出現的次數並不是很多,有些是在路由類中。

您可以在Visual Studio中取消選中「Just my code」並調試ASP.NET MVC代碼。