2009-11-04 16 views
6

Mam aplikację internetową korzystającą z MVC 2 Preview 2 i po zarejestrowaniu wszystkich tras, muszę owinąć każdą trasę w dekoratorze w dalszej części łańcucha. Problem polega na tym, że w ten sposób łamie routing. Co się dzieje, to metoda GetVirtualPath będzie pasować fałszywie do innych obszarów w aplikacji (korzystam z pojedynczych obszarów projektu). Nie ma znaczenia, czy dekorator zrobi coś użytecznego, czy nie. Korzystanie z poniższego przekazu jest wszystkim, czego potrzebujesz, aby je złamać.Dlaczego trasa dekoracyjna trasy przerwać routing w 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); 
    } 
} 

Przypisuję dekoratorowi prostą pętlę po zarejestrowaniu wszystkich tras.

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

Jak mogę bezpiecznie wstawić dekorator bez zrywania ścieżek i obszarów?

Mam dostępne rozwiązanie do reprodukcji to download here. W reprodukcji, dekorator trasy jest wykomentowany. Wpisanie go ponownie spowoduje przerwanie routingu, a pierwsze dane routingu obszaru dummy będą odpowiadać liniom, które normalnie będą poprawnie pasować tylko do odpowiedniej przestrzeni nazw.

Odpowiedz

5

Myślę, że to zależy od tego, w jaki sposób obszary używają słownika DataTokens do przechowywania informacji o obszarze/przestrzeni nazw. Ponieważ dziedziczysz z RouteBase, prawdopodobnie musisz zaimplementować interfejs IRouteWithArea, ponieważ nie masz DataTokens, które ma Trasa.

actionlink pomocnik wydaje się pośrednio nazywają to stąd potrzeba nowego interfejsu:

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] wierzę dodaje rozwiąże problemu, ponieważ dekorator wydaje się skończyć owijania trasę więcej niż raz:

dodatkowe nieruchomość na dekoratora:

public RouteBase InnerRoute 
     { 
      get 
      { 
       return _route; 
      } 
     } 

implementacja interfejsu:

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

Dzięki za wysiłek. Implementacja IRouteWithArea nie koryguje problemu carte blanche, ale może to doprowadzić mnie w nowym kierunku. Dziękuję Ci. –

+0

Wygląda na to, że dekorator kończy się owijaniem trasy więcej niż jeden raz. Edytowałem swoją odpowiedź, podając kod do wdrożenia działającego rozwiązania, choć najlepiej chciałbym dowiedzieć się, dlaczego tak się dzieje, ponieważ jest to dość dziwne. –

+0

To zdecydowanie odpowiedź na problem. Nie złapałem problemu z dekoratorem odradzania. Jest to dziwne zachowanie lub oczekiwane zachowanie z brakiem zrozumienia, dlaczego tak się dzieje. –

0

Co się dzieje, jeśli ozdobić klasę Route zamiast RouteBase?

wymyślić coś takiego:

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

Polecam również sprawdzanie System.Web.Routing.dll z reflektorem, to może dać wgląd w to, co się dzieje.

A także, co się stanie, jeśli to zrobić:

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

Mam wielką nadzieję, że to pomaga.

+0

Nie mogę używać Route zamiast RouteBase, ponieważ RouteCollection jest zbiorem RouteBase. Użyłem Reflectora i kodu źródłowego MVC 2, aby spróbować wydedukować problem przed opublikowaniem go tutaj. Twoja druga sugestia (czyszczenie kolekcji?) Nie ma żadnego efektu. –

Powiązane problemy