2012-03-30 10 views
0

foo/{controller}/{action}/{id}という単一のルートマップを持つエリアFooがあります。asp.net mvcエリアは別のエリアの一部としてルーティングされます

また、別の領域、Barがあります。これは本質的にこの領域のサブコンポーネントです。マップされた経路はfoo/bar/{controller}/{action}/{id}です。

たとえば、BarエリアにコントローラBazControllerがあるため、foo/bar/bazのようなルートを設定できます。

これに伴う問題は、私のマッピングされたルートがfoo/bar/{controller}/{action}/{id}

Iで宣言されたルートに代わりマッピングのBarControllerという名前のコントローラを探しているように見えるようルートは、このシナリオのために解決していないようだということです私は無意識に違反した基本的な設計コンセプトがあると仮定しています...もしそうなら、どのように2つの領域を持つ代わりにこれを構成すべきですか?

URLルーティングの私の主な理解はDjangoバックグラウンドから来ています。そこでは、別々のURLファイルを参照するようなことができ、すべてのルートはトップダウン形式で処理されます。私は経路マッピングの優先順位がasp.net mvcでどのように決定されるのか分かりませんし、経路登録の順序がどのようにエリアで行われているのか分かりません。

UPDATE

@zLanが示唆したように、私はフィル・ハークのルートデバッガを使用し、それは確かに私のマッピングされたルートの両方にマッチする、といくつかの理由で1上Foo地域に指定されたルートに優先を取っていますBarエリアで指定されています。

私はそれをさらにデバッグし、それぞれのRegisterAreaメソッドの代わりにGlobal.asaxで両方のルートを指定しました。@mfantoが提案したように、最初に宣言されたルートを選択するようです。

私の追随する質問は次のとおりです。最初に登録する領域を指定/決定するにはどうすればよいですか?それが信頼できる条約ではない場合、URL foo/bar/bazが私のBarエリアに解決するような方法でこれらのルートを宣言するには、受け入れ可能な方法がありますか?Global.asaxのすべてを宣言する必要はありませんか?

+0

フィル・ハークは素晴らしい[ルートデバッガ](http://haacked.com/archive/2008/03/を持っています13/url-routing-debugger.aspx)を使用して、ルートがどこにあるかを知らせます。 –

+0

これまでに作成したルートのリストを貼り付けることはできますか? – mfanto

答えて

0

この問題は、エリアルートが登録される順序に関連しているようです。エリアルートがどのようにマップされているかについての決定的な文書が見つからなかったので、特定の順序に依存するのは安全だとは思わないので、別のクラス内で呼び出すことができるルーティングをカプセル化する新しいクラスを作成しましたroutesファイル。これは、基本的に領域を「モジュール化」するので、他のURLプレフィックスに追加するルートのセットとして使用できます。

基本的な考え方は、私がFooAreaRegistration内で次のような何かを行うことができるようにDjango's ability to include other urlconfsをエミュレートすることです:

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さんのコメントをエコーするために、フィルのルートデバッガは、このような問題を修正するのに最適です。

+0

両方のルートを 'Global.asax'で宣言すると、宣言された最初のルートを受け入れるようです。このようにすると、指定したエリア内にすべてのルート登録を保持するという目的を破るように見えます。おそらく、私が "入れ子になった"地域でやっていることは、とにかくそうする必要があるのでしょうか? –

関連する問題