8

Podczas próby utworzenia catch all route w MVC 4 (coś, co znalazłem kilka przykładów i na podstawie mojego kodu) zwraca błąd 404. Używam tego w IIS 7.5. To wydaje się proste rozwiązanie, więc czego mi brakuje?MVC 4 catch all route never reached

Jedna uwaga, jeśli przeniesię trasę "CatchAll" powyżej trasy "Default", to działa. Ale oczywiście wtedy żaden z innych kontrolerów nie zostanie osiągnięty.

Oto kod:

Route.Config:

 routes.MapRoute(
      name: "Default", 
      url: "{controller}/{action}/{id}", 
      defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
     ); 

     routes.MapRoute(
      "CatchAll", 
      "{*dynamicRoute}", 
      new { controller = "CatchAll", action = "ChoosePage" } 
     ); 

Kontroler:

public class CatchAllController : Controller 
{ 

    public ActionResult ChoosePage(string dynamicRoute) 
    { 
     ViewBag.Path = dynamicRoute; 
     return View(); 
    } 

} 

Odpowiedz

9

Ponieważ ostatecznym celem stworzenia trasy catchall było być w stanie obsługiwać dynamiczne adresy URL i nie udało mi się znaleźć bezpośredniej odpowiedzi do oryginalny numer powyżej, podszedłem do moich badań z innej perspektywy. W ten sposób natknąłem tym blogu: Custom 404 when no route matches

To rozwiązanie umożliwia obsługę wielu sekcji w danym url (tj www.mysite.com/this/is/a/dynamic/route)

Tutaj to końcowy niestandardowy kod kontrolera:

public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) 
{ 
    if (requestContext == null) 
    { 
     throw new ArgumentNullException("requestContext"); 
    } 

    if (String.IsNullOrEmpty(controllerName)) 
    { 
     throw new ArgumentException("MissingControllerName"); 
    } 

    var controllerType = GetControllerType(requestContext, controllerName); 

    // This is where a 404 is normally returned 
    // Replaced with route to catchall controller 
    if (controllerType == null) 
    { 
     // Build the dynamic route variable with all segments 
     var dynamicRoute = string.Join("/", requestContext.RouteData.Values.Values); 

     // Route to the Catchall controller 
     controllerName = "CatchAll"; 
     controllerType = GetControllerType(requestContext, controllerName); 
     requestContext.RouteData.Values["Controller"] = controllerName; 
     requestContext.RouteData.Values["action"] = "ChoosePage"; 
     requestContext.RouteData.Values["dynamicRoute"] = dynamicRoute; 
    } 

    IController controller = GetControllerInstance(requestContext, controllerType); 
    return controller; 
} 
+2

To działa dobrze. Możesz uniknąć foreach i substring, jeśli to zrobisz: 'var dynamicRoute = string.Join ("/", requestContext.RouteData.Values.Values);' –

+0

Dobre połączenie Nathan. Minęło trochę czasu, odkąd spojrzałem na ten kod. Zawsze znajduję sposoby na ulepszenie starego kodu. To z pewnością jeden z tych czasów. Zaktualizowałem odpowiedź, podając Twoją sugestię. Dzięki! – gsxrboy73

+0

SO jest na to świetny, uczę się czegoś prawie za każdym razem, kiedy tu przyjeżdżam. Ten kod był świetny, próbowałem dowiedzieć się, czy chcę to obsłużyć w kontrolerze bazowym, ale przekazanie go do fabryki kontrolerów to lepszy pomysł! –

4

To pewnie dlatego, że cokolwiek trasa your're testowania to jest zgodne z 1st - default trasa. Sposób działania routingu w MVC, każdy adres, który podasz, spróbuje dopasować trasy w kolekcji tras w kolejności ich pojawiania się. Po znalezieniu pierwszej pasującej trasy przerywa dalszą realizację. W tym przypadku Twoja trasa domyślna jest pierwsza na liście, więc jeśli zostanie dopasowana, twoja druga trasa nigdy nie zostanie zbadana.

Zasadniczo wpisz na pasku adresu coś podobnego do http://www.mysite.com/Home/Testing/Item/Page, co nie powinno pasować do trasy domyślnej, a następnie spróbuj dopasować trasę CatchAll.

+1

Oto testowana przeze mnie strona: http://mysite.com/hello, do której nie mam kontrolerów. – gsxrboy73

+1

Nie ma znaczenia, jeśli nie masz kontrolera dla trasy, nadal wybiera pierwszą sekwencyjną pasującą trasę, niezależnie ("Domyślne" w tym przypadku). Będzie szukać klasy HelloController: kontroler z akcją Index i jeśli go nie znajdzie, otrzymasz 404. – cchamberlain

0

Spróbuj zdefiniowania opcjonalny parametr ciąg dynamicRoute na trasie:

routes.MapRoute( 
     "CatchAll", 
     "{*dynamicRoute}", 
     new { controller = "CatchAll", action = "ChoosePage", dynamicRoute = UrlParameter.Optional }); 
+0

Po prostu wypróbowałem to, ten sam wynik. Dzieki za probe. – gsxrboy73