ASP.NET MVC - Catch All Route And Default Route

asp.net Mvcasp.net Mvc-2

asp.net Mvc Problem Overview


In trying to get my application to produce 404 errors correctly, I have implemented a catch all route at the end of my route table, as shown below:

 routes.MapRoute(
            "NotFound", _
           "{*url}", _
           New With {.controller = "Error", .action = "PageNotFound"} _
       )

However, to get this working, I had to remove the default route:

{controller}/action/{id}

But now that the default has been removed, most of my action links no longer work, and the only way I have found to get them working again is to add individual routes for each controller/action.

Is there a simpler way of doing this, rather than adding a route for each controller/action?

Is it possible to create a default route that still allows the catch all route to work if the user tries to navigate to an unknown route?

asp.net Mvc Solutions


Solution 1 - asp.net Mvc

Use route constraints

In your case you should define your default route {controller}/{action}/{id} and put a constraint on it. Probably related to controller names or maybe even actions. Then put the catch all one after it and it should work just fine.

So when someone would request a resource that fails a constraint the catch-all route would match the request.

So. Define your default route with route constraints first and then the catch all route after it:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = "Home|Settings|General|..." } // this is basically a regular expression
);
routes.MapRoute(
    "NotFound",
    "{*url}",
    new { controller = "Error", action = "PageNotFound" }
);

Solution 2 - asp.net Mvc

//this catches all  requests
routes.MapRoute(
    "Error",
    "{*.}",
     new { controller = "PublicDisplay", action = "Error404" } 
);

add this route at the end the routes table

Solution 3 - asp.net Mvc

Ah, the problem is your default route catches all 3 segment URLs. The issue here is that Routing runs way before we determine who is going to handle the request. Thus any three segment URL will match the default route, even if it ends up later that there's no controller to handle it.

One thing you can do is on your controller override the HandleMissingAction method. You should also use the tag to catch all 404 issues.

Solution 4 - asp.net Mvc

Well, what I have found is that there is no good way to do this. I have set the redirectMode property of the customErrors to ResponseRewrite.

<customErrors mode="On" defaultRedirect="~/Shared/Error" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="~/Shared/PageNotFound"/>
</customErrors>

This gives me the sought after behavior, but does not display the formatted page.

To me this is poorly done, as far as SEO goes. However, I feel there is a solution that I am missing as SO does exactly what I want to happen. The URL remains on the failed page and throws a 404. Inspect stackoverflow.com/fail in Firebug.

Solution 5 - asp.net Mvc

My Solution is 2 steps.

I originally solved this problem by adding this function to my Global.asax.cs file:

protected void Application_Error(Object sender, EventArgs e)

Where I tried casting Server.GetLastError() to a HttpException, and then checked GetHttpCode. This solution is detailed here:

https://stackoverflow.com/questions/1171035/asp-net-mvc-custom-error-handling-application-error-global-asax

This isn't the original source where I got the code. However, this only catches 404 errors which have already been routed. In my case, that ment any 2 level URL.

for instance, these URLs would display the 404 page:

www.site.com/blah

www.site.com/blah/blah

however, www.site.com/blah/blah/blah would simply say page could not be found. Adding your catch all route AFTER all of my other routes solved this:

routes.MapRoute(
            "NotFound",
            "{*url}",
            new { controller = "Errors", action = "Http404" }
        );

However, the NotFound route does not seem to route requests which have file extensions. This does work when they are captured by different routes.

Solution 6 - asp.net Mvc

I would recommend this as the most readable version. You need this in your RouteConfig.cs, and a controller called ErrorController.cs, containing an action 'PageNotFound'. This can return a view. Create a PageNotFound.cshtml, and it'll be returned in response to the 404:

        routes.MapRoute(
            name:  "PageNotFound",
            url:  "{*url}",
            defaults: new { controller = "Error", action = "PageNotFound" }
        );

How to read this:

name: "PageNotFound"

= create a new route template, with the arbitrary name 'PageNotFound'

url:"{*url}"

= use this template to map all otherwise unhandled routes

defaults: new { controller = "Error", action = "PageNotFound" }

= define the action that an incorrect path will map to (the 'PageNotFound' Action Method in the Error controller). This is needed since an incorrectly entered path will not obviously not map to any action method

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSean TaylorView Question on Stackoverflow
Solution 1 - asp.net MvcRobert KoritnikView Answer on Stackoverflow
Solution 2 - asp.net MvcPraveen PrasadView Answer on Stackoverflow
Solution 3 - asp.net MvcHaackedView Answer on Stackoverflow
Solution 4 - asp.net MvcDustin LaineView Answer on Stackoverflow
Solution 5 - asp.net MvcMarcus10110View Answer on Stackoverflow
Solution 6 - asp.net MvcChris HalcrowView Answer on Stackoverflow