2009-11-04 4 views
6

Ich habe eine Web-Anwendung mit MVC 2 Preview 2 und nachdem alle Routen registriert sind, muss ich jede Route in einem Dekorator weiter unten in der Kette wickeln. Das Problem ist, das Routing zu unterbrechen. Am Ende wird die GetVirtualPath-Methode fälschlicherweise für andere Bereiche in der Anwendung übereinstimmen (ich verwende Einzelprojektbereiche). Es spielt keine Rolle, ob der Dekorateur etwas Nützliches tut oder nicht. Mit dem folgenden Passthrough brauchen Sie nur, um es zu brechen.Warum unterbrechen Routenplaner das Routing in ASP.NET MVC 2?

public class RouteDecorator: RouteBase 
{ 
    readonly RouteBase _route; 

    public RouteDecorator(RouteBase route) 
    { 
     _route = route; 
    } 

    public override RouteData GetRouteData(HttpContextBase context) 
    { 
     return _route.GetRouteData(context); 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext context, RouteValueDictionary values) 
    { 
     return _route.GetVirtualPath(context, values); 
    } 
} 

Ich ordne den Dekorator in einer einfachen Schleife, nachdem alle Routen registriert sind.

var routes = RouteTable.Routes; 
for (var i = 0; i < routes.Count; i++) 
{ 
    routes[i] = new RouteDecorator(routes[i]); 
} 

Wie kann ich einen Dekorateur sicher einfügen, ohne Routen und Bereiche zu unterbrechen?

Ich habe eine Reproduktionslösung verfügbar to download here. In der Reproduktion ist der Routenbildner auskommentiert. Ein erneutes Kommentieren unterbricht das Routing, und die Routing-Daten des ersten Dummy-Bereichs stimmen mit den Links überein, die normalerweise nur dem entsprechenden Namespace entsprechen.

Antwort

5

Ich denke, es liegt an der Art und Weise, in der Bereiche das DataTokens-Wörterbuch verwenden, um die Area/Namespace-Informationen zu speichern. Da Sie von RouteBase geerbt haben, müssen Sie wahrscheinlich auch die Schnittstelle IRouteWithArea implementieren, da Sie nicht über die DataTokens verfügen, die eine Route besitzt.

Die Action Helfer scheint indirekt dies für diese neue Schnittstelle daher die Notwendigkeit zu nennen:

public static string GetAreaName(RouteBase route) 
{ 
    IRouteWithArea area = route as IRouteWithArea; 
    if (area != null) 
    { 
     return area.Area; 
    } 
    Route route2 = route as Route; 
    if ((route2 != null) && (route2.DataTokens != null)) 
    { 
     return (route2.DataTokens["area"] as string); 
    } 
    return null; 
} 

[Edit - 2009-11-12] ich folgenden glaube das Problem zu beheben, wie die Dekorateur scheint die Strecke mehr als einmal am Ende Verpackung:

Außerdem steht auf Dekorateur:

public RouteBase InnerRoute 
     { 
      get 
      { 
       return _route; 
      } 
     } 

Schnittstellenimplementierung:

public string Area 
     { 
      get 
      { 

       RouteBase r = _route; 
       while (r is RouteDecorator) 
        r = ((RouteDecorator) r).InnerRoute; 
       string s = GetAreaToken(r); 
       if (s!= null) return s; 
       return null; 
      } 
     } 

     private string GetAreaToken(RouteBase r) 
     { 
      var route = r as Route; 
      if (route != null && route.DataTokens !=null && route.DataTokens.ContainsKey("area")) 
      { 
       return (route.DataTokens["area"] as string); 
      } 
      return null; 
     } 
    } 
+0

Danke für die Mühe. Das Implementieren von IRouteWithArea korrigiert das Problem Carte Blanche nicht, aber es könnte mich in eine neue Richtung führen. Vielen Dank. –

+0

Der Decorator scheint die Route mehr als einmal zu umhüllen. Ich habe meine Antwort mit dem Code für die Implementierung einer funktionierenden Lösung bearbeitet, obwohl ich im Idealfall herausfinden möchte, warum dies passiert, da es ziemlich seltsam ist. –

+0

Dies ist definitiv die Antwort auf das Problem. Ich habe das Thema "Laichdekorateur" nicht verstanden. Dies ist ein seltsames Verhalten oder ein erwartetes Verhalten mit einem Mangel an Verständnis, warum es passiert. –

0

Was passiert, wenn Sie die Route-Klasse statt RouteBase dekorieren?

Denken Sie an etwas wie folgt aus:

public class RouteDecorator: Route 
{ 
    readonly Route _route; 

    public RouteDecorator(Route route) 
    { 
     _route = route; 
    } 

    public override RouteData GetRouteData(HttpContextBase context) 
    { 
     return _route.GetRouteData(context); 
    } 

    public override VirtualPathData GetVirtualPath(RequestContext context, RouteValueDictionary values) 
    { 
     return _route.GetVirtualPath(context, values); 
    } 
} 

Ich empfehle auch System.Web.Routing.dll mit Reflektor Check-out, es könnte Ihnen einen Einblick von dem, was geschieht.

Und auch, was passiert, wenn Sie dies tun:

var routes = RouteTable.Routes.ToList(); 
RouteTable.Routes.Clear(); 
//or, alternatively, if the above doesn't work: 
//RouteTable.Routes = new RouteCollection(); 
foreach (var r in routes) 
{ 
    RouteTable.Routes.Add(new RouteDecorator(r)); 
} 

Ich hoffe sehr, dass es hilft.

+0

Ich kann Route nicht als RouteBase verwenden, da RouteCollection eine Sammlung von RouteBase ist. Ich habe Reflector und den MVC 2-Quellcode verwendet, um das Problem abzuleiten, bevor ich es hier poste. Ihr anderer Vorschlag (Löschen der Sammlung?) Hat keine Wirkung. –