2012-03-30 65 views
0

我有一個區域,Foo,它具有映射的單個路由:foo/{controller}/{action}/{id}asp.net mvc區域作爲另一個區域的一部分路由

我也有另一個區域,Bar,這實質上是這個區域的一個子組件。它具有映射路線foo/bar/{controller}/{action}/{id}。因此,例如,我在我的Bar區域內有一個名爲BazController的控制器,因此我可以有一條類似foo/bar/baz的路線。

這樣做的問題是,路線似乎並沒有爲解決這種情況,因爲它似乎是我的映射路線正在尋找一個名爲BarController,而不是映射與foo/bar/{controller}/{action}/{id}

我宣佈路由控制器假設有一些基本的設計理念,我不知不覺地違反了......如果是這樣的話,我應該如何組織這個,而不是有兩個領域?

我對url路由的基本理解來自Django背景,您可以在其中執行諸如引用單獨url文件之類的內容,並且所有路由都以自頂向下的方式進行處理。我不知道如何使用asp.net mvc確定路由映射優先級,也不知道如何對區域進行路由註冊排序。

UPDATE

我用菲爾哈克的路線調試器@zLan建議,它確實是匹配在我的兩個映射路線,出於某種原因,採取優先於Foo面積超過了一個指定的路線在Bar區域指定。

我進一步調試它,並且在Global.asax中而不是在其各自的RegisterArea方法中指定了兩個路由,就像@mfanto建議的那樣,它似乎選擇了首先聲明的路由。

我的後續問題是:我如何指定/確定哪個區域會首先被註冊?如果這不是一個可靠的公約,是否有一種可接受的方式來聲明這些路線,以便網址foo/bar/baz將解析爲我的Bar區域,而無需在Global.asax中聲明它們全部?

+0

菲爾哈克有很大的[路線調試器(http://haacked.com/archive/2008/03/ 13/url-routing-debugger.aspx),讓你知道你的路線在哪裏。 – 2012-03-30 16:08:27

+0

您可以粘貼到目前爲止創建的路線列表嗎? – mfanto 2012-03-30 16:11:32

回答

0

這個問題似乎與地區路線登記的順序有關。由於我沒有找到有關區域路線如何映射的確鑿文檔,也不認爲依賴任何特定順序是安全的,我繼續創建一個新類來封裝我可以從不同的路徑調用的路由路線文件。這基本上「模塊化」了一個區域,以便它可以用作一組路由來附加到其他一些URL前綴。

的基本思想是仿效Django's ability to include other urlconfs,這樣我可以做類似下面的內FooAreaRegistration

public override void RegisterArea(AreaRegistrationContext context) 
{ 
    new BarAreaModule().RegisterRoutes(namePrefix:"bar", urlPrefix:"foo/", context.Routes); 

    context.MapRoute("foo_default", "foo/{controller}/{action}/{id}", new{controller="Default", action="Index", id=UrlParameter.Optional}); 
} 

,並擁有所有的路線獲得註冊以有序的方式,使foo/bar沒有得到混淆``foo_default「路線。

以下是AreaModule類的全部源代碼,任何人這是興趣:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Mvc; 
using System.Web.Routing; 

namespace Gov.Wa.Hecb.UI.Portal.Areas 
{ 
    /// <summary> 
    /// Allows a group of functionality to be registered to any given url prefix. This is to be used to replace an Area in cases 
    /// where an Area is either a sub-module to another area, or if an area's functionality is to be parameterized and reused in 
    /// multiple urls. 
    /// </summary> 
    public abstract class AreaModule 
    { 
     public abstract string AreaName { get; } 

     /// <summary> 
     /// Registers all routes necessary for this Module to function with the given url prefix 
     /// </summary> 
     /// <param name="namePrefix"></param> 
     /// <param name="urlPrefix">a slash-appended string representing the url to match up to the module</param> 
     /// <param name="routes"></param> 
     public void RegisterRoutes(string namePrefix, string urlPrefix, RouteCollection routes) 
     { 
      if (string.IsNullOrEmpty(namePrefix)) 
       throw new ArgumentException("namePrefix cannot be null or empty", "namePrefix"); 
      if (string.IsNullOrEmpty(urlPrefix)) 
       throw new ArgumentException("urlPrefix cannot be null or empty", "urlPrefix"); 
      if (routes == null) 
       throw new ArgumentNullException("routes"); 

      var context = new AreaModuleContext(AreaName, namePrefix, urlPrefix, routes); 
      var thisNamespace = GetType().Namespace; 
      if (thisNamespace != null) 
       context.Namespaces.Add(thisNamespace + ".*"); 

      RegisterRoutes(context); 
     } 

     protected abstract void RegisterRoutes(AreaModuleContext context); 
    } 

    public class AreaModuleContext 
    { 
     #region Private 

     private readonly HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 

     #endregion 

     #region Constructors 

     public AreaModuleContext(string areaName, string namePrefix, string urlPrefix, RouteCollection routes, object state = null) 
     { 
      if (String.IsNullOrEmpty(areaName)) 
       throw new ArgumentException("areaName cannot be null or empty", "areaName"); 
      if (string.IsNullOrEmpty(namePrefix)) 
       throw new ArgumentException("namePrefix cannot be null or empty", "namePrefix"); 
      if (string.IsNullOrEmpty(urlPrefix)) 
       throw new ArgumentException("urlPrefix cannot be null or empty", "urlPrefix"); 
      if (routes == null) 
       throw new ArgumentNullException("routes"); 

      AreaName = areaName; 
      NamePrefix = namePrefix; 
      UrlPrefix = urlPrefix; 
      Routes = routes; 
      State = state; 
     } 


     #endregion 

     #region Properties 

     public string AreaName { get; private set; } 

     public string NamePrefix { get; private set; } 

     public string UrlPrefix { get; private set; } 

     public ICollection<string> Namespaces 
     { 
      get { return _namespaces; } 
     } 

     public RouteCollection Routes { get; private set; } 

     public object State { get; private set; } 

     #endregion 

     #region Route Mapping 

     public Route MapRoute(string name, string url) 
     { 
      return MapRoute(name, url, (object) null /* defaults */); 
     } 

     public Route MapRoute(string name, string url, object defaults) 
     { 
      return MapRoute(name, url, defaults, (object) null /* constraints */); 
     } 

     public Route MapRoute(string name, string url, object defaults, object constraints) 
     { 
      return MapRoute(name, url, defaults, constraints, null /* namespaces */); 
     } 

     public Route MapRoute(string name, string url, string[] namespaces) 
     { 
      return MapRoute(name, url, null /* defaults */, namespaces); 
     } 

     public Route MapRoute(string name, string url, object defaults, string[] namespaces) 
     { 
      return MapRoute(name, url, defaults, null /* constraints */, namespaces); 
     } 

     public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) 
     { 
      if (namespaces == null && Namespaces != null) 
       namespaces = Namespaces.ToArray(); 

      var route = Routes.MapRoute(NamePrefix + name, UrlPrefix + url, defaults, constraints, namespaces); 
      route.DataTokens["area"] = AreaName; 

      // disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up 
      // controllers belonging to other areas 
      var useNamespaceFallback = (namespaces == null || namespaces.Length == 0); 
      route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback; 

      return route; 
     } 

     #endregion 
    } 
} 
0

在Global.asax中爲RegisterRoutes()添加類似如下的內容爲路由工作嗎?

routes.MapRoute(
       "Default", // Route name 
       "foo/bar/{controller}/{action}/{id}", // URL with parameters 
       new { area = "Bar", controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
      ); 

爲了迴應zLan的評論,Phil的Route Debugger非常適合解決這樣的問題。

+0

通過在'Global.asax'中聲明兩條路由,它似乎接受聲明的第一條路由。這樣做似乎破壞了將所有路線註冊保留在指定區域內的目的。也許我在「嵌套」區域做的事情需要我這樣做呢? – 2012-03-30 17:19:27