2012-03-30 13 views
0

geroutet Ich habe einen Bereich, Foo, der eine einzige Route zugeordnet hat: foo/{controller}/{action}/{id}.asp.net mvc Bereich als Teil eines anderen Bereichs

Ich habe auch einen anderen Bereich, Bar, die im Wesentlichen eine Unterkomponente dieses Bereichs ist. Es hat eine Karte Route von foo/bar/{controller}/{action}/{id}.

So habe ich zum Beispiel einen Controller namens BazController in meinem Bar Bereich, so dass ich eine Route haben kann, die wie foo/bar/baz aussieht.

Das Problem dabei ist, dass die Routen scheinen nicht für dieses Szenario zu lösen, wie es meine kartiert Routen suchen einen Controller mit foo/bar/{controller}/{action}/{id}

Ich erklärte BarController statt Abbildung auf der Route genannt scheint, dass Ich nehme an, es gibt ein grundlegendes Design-Konzept, das ich unbeabsichtigt verletzt habe ... Wenn das der Fall ist, wie sollte ich das organisieren, anstatt zwei Bereiche zu haben?

Mein primäres Verständnis von URL-Routing kommt von einem Django-Hintergrund, wo Sie Zeug wie Referenz separate URL-Dateien tun können und alle Routen werden in einer Top-Down-Mode verarbeitet. Ich weiß nicht, wie Route Mapping-Präzedenzfall mit asp.net mvc bestimmt ist, und habe keine Ahnung, wie die Reihenfolge der Routenregistrierung mit Bereichen erfolgt. in Foo Bereich über einen

UPDATE

ich Phil Haack Route Debugger verwendet als @zLan vorgeschlagen, und es in der Tat auf meine beiden abgebildeten Routen ist passend, und aus irgendeinem Grund angegeben Vorrang auf die Route nehmen im Bereich Bar angegeben.

Ich debuggte es weiter und spezifizierte beide Routen in Global.asax statt in ihren jeweiligen RegisterArea Methoden wie @mfanto vorgeschlagen, und es scheint die Route zu wählen, die zuerst erklärt wurde.

Meine Follow-up-Frage lautet dann: Wie kann ich bestimmen/bestimmen, welcher Bereich zuerst registriert wird? Und wenn das keine zuverlässige Konvention ist, gibt es eine akzeptable Möglichkeit, diese Routen so zu deklarieren, dass die URL foo/bar/baz in meinen Bereich Bar aufgelöst wird, ohne sie alle in Global.asax deklarieren zu müssen?

+0

Phil Haack hat eine große [Routen Debugger] (http://haacked.com/archive/2008/03/ 13/url-routing-debugger.aspx), damit Sie wissen, wohin Ihre Routen gehen. –

+0

Können Sie die Liste der Routen einfügen, die Sie bisher erstellt haben? – mfanto

Antwort

0

Das Problem scheint mit der Reihenfolge in Verbindung zu stehen, in der Bereichsrouten registriert werden. Da ich keine schlüssige Dokumentation darüber gefunden habe, wie Gebietsrouten abgebildet werden, und nicht sicher bin, dass man sich auf eine bestimmte Reihenfolge verlassen kann, habe ich eine neue Klasse erstellt, um das Routing, das ich aufrufen kann, in ein anderes zu kapseln Routen-Datei. Dies "modularisiert" im Grunde einen Bereich, so dass er als eine Reihe von Routen verwendet werden kann, die an ein anderes URL-Präfix angehängt werden.

Die Grundidee ist Django's ability to include other urlconfs zu emulieren, so dass ich etwas wie die folgenden innerhalb FooAreaRegistration tun könnte:

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

und habe alle Routen in einer geordneten Art und Weise registrieren lassen, so dass foo/bar nicht verwirrt bekommen mit die Route "foo_default".

Hier finden Sie die gesamte Quelle der AreaModule Klasse, für jeden, der interessiert ist:

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

Fügt RegisterRoutes() in Global.asax etwas wie folgt für die Route hinzu?

Um den Kommentar von zLan zu beantworten, ist Phils Route Debugger ideal, um solche Probleme zu beheben.

+0

durch Deklarieren der beiden Routen in 'Global.asax' scheint es die erste deklarierte Route zu akzeptieren. So zu tun scheint den Zweck zu vereiteln, alle Ihre Routenregistrierungen innerhalb des angegebenen Bereichs zu halten. Vielleicht, was ich mache, indem ich Bereiche "verschachtel", muss ich das trotzdem tun? –

Verwandte Themen