8

When attempting to create a catch all route in MVC 4 (something I've found several examples of, and based my code on) it returns a 404 error. I'm running this on IIS 7.5. This seems like a straight forward solution, so what am I missing?

One note, if I move the "CatchAll" route above the "Default" route it works. But of course then none of the other controllers are ever reached.

Here is the code:

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

Controller:

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

3 Answers 3

10

Since the ultimate goal of creating the catchall route was to be able to handle dynamic urls and I was unable to find a direct answer to the original issue above, I approached my research from a different perspective. In doing so I came across this blog post: Custom 404 when no route matches

This solution allows handling of multiple sections within a given url (i.e. www.mysite.com/this/is/a/dynamic/route)

Here is the final custom controller code:

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; } 
Sign up to request clarification or add additional context in comments.

3 Comments

This works well. You can avoid the foreach and substring if you do this: var dynamicRoute = string.Join("/", requestContext.RouteData.Values.Values);
Good call Nathan. Been awhile since I looked at this code. I always find ways to improve old code. This is certainly one of those times. I've updated the answer with your suggestion. Thanks!
SO is great for that, I learn something almost every time I come here. This code was great, I was trying to figure out if I wanted to handle this in a base controller, but pushing it up to the controller factory is a better idea!
4

It's probably because whatever route your're testing this with is matching your 1st - Default route. The way the routing in MVC works, any address you pass in will try to match routes in your routes collection in order of appearance. Once it find the 1st matching route it aborts further execution. In this case your Default route is 1st one in the list so if it is matched your second route will never be examined.

Basically write something like http://www.mysite.com/Home/Testing/Item/Page in your address bar and this should fail to match to your Default route and then try to match the CatchAll route.

2 Comments

This is the route I'm testing: mysite.com/hello, which I have no controllers for.
It doesn't matter if you don't have a controller for the route, its still going to pick the first sequential matching route regardless ("Default" in this case). It will look for a class HelloController : Controller with Index action and if it doesn't find it, you will get the 404.
0

Try defining the optional string dynamicRoute parameter on your route:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.