52

Is it possible to create a final route that catches all .. and bounces the user to a 404 view in ASP.NET MVC?

NOTE: I don't want to set this up in my IIS settings.

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
  • See my answer to "http://stackoverflow.com/questions/619895/how-can-i-properly-handle-404-in-asp-net-mvc/23830145#23830145". – Herman Kan May 23 '14 at 13:16

8 Answers8

81

Found the answer myself.

Richard Dingwall has an excellent post going through various strategies. I particularly like the FilterAttribute solution. I'm not a fan of throwing exceptions around willy nilly, so i'll see if i can improve on that :)

For the global.asax, just add this code as your last route to register:

routes.MapRoute(
    "404-PageNotFound",
    "{*url}",
    new { controller = "StaticContent", action = "PageNotFound" }
    );
Pure.Krome
  • 84,693
  • 113
  • 396
  • 647
  • 7
    I've tried this, but it doesn't work. I have put the route under my default route, but i still get 404 errors. – Martijn Apr 09 '09 at 12:48
  • Can you please explain what exactly I have to assuming I am very new to MVC. – Tanmoy Jun 16 '09 at 12:57
  • 2 things. a) add that last route to your route list. b) create a controller (in my example, i called it StaticContentController) with an Action method (in my example, i added a method called PageNotFound(..)) add logic this method to display the 404 page not found, View. – Pure.Krome Jun 17 '09 at 03:08
  • 34
    If you still have the default route (I.E. {controller}/{action}/{id}) in RegisterRoutes() it will trap all URLs that match the format of a normal MVC request. In other words the catch-all route can only intercept a bad URL if it doesn't fit the normal format (**blah/blah/blah/blah**). In the case of a non-existent controller the exception must be handled through conventional ASP.NET handling. Theres a good description of handling at http://stackoverflow.com/questions/619895/how-can-i-properly-handle-404s-in-asp-net-mvc/620559#620559 – RonnBlack Jul 14 '09 at 01:38
  • Indeed the 'catch all' is maybe not the best approach. Feedback on this answer pls: http://stackoverflow.com/questions/619895/how-can-i-properly-handle-404s-in-asp-net-mvc/2577095#2577095 – Matt Kocaj Apr 05 '10 at 06:19
  • 4
    @RonnBlack is right. I overcome this by just explicitly create a route for each controller. BUT the magic `{*url}` still not overcome this issue. What if the mapped URL into route is available but the controller/action itself did not found. If I browse to /Home/About123 ugly asp.net error page still come out because the route not reach to the `{*url}` but handled in my home route. – CallMeLaNN May 19 '11 at 08:21
  • Make sure that your routes are mapped in the correct order. – Captain Kenpachi Apr 29 '14 at 08:07
  • @Pure.Krome: is it not in your Routeconfig you must add the code. – H. Pauwelyn Nov 10 '15 at 14:27
20

This question came first, but the easier answer came in a later question:

Routing for custom ASP.NET MVC 404 Error page

I got my error handling to work by creating an ErrorController that returns the views in this article. I also had to add the "Catch All" to the route in global.asax.

I cannot see how it will get to any of these error pages if it is not in the Web.config..? My Web.config had to specify:

customErrors mode="On" defaultRedirect="~/Error/Unknown"

and then I also added:

error statusCode="404" redirect="~/Error/NotFound"

Hope this helps.

I love this way now because it is so simple:

 <customErrors mode="On" defaultRedirect="~/Error/" redirectMode="ResponseRedirect">
    <error statusCode="404" redirect="~/Error/PageNotFound/" />
 </customErrors>
Community
  • 1
  • 1
smdrager
  • 7,327
  • 6
  • 39
  • 49
  • That's what I have now, but I'm trying to replace it with a better solution which will not first send a 302 response to the client but a 404 directly. Change the redirectMode to ResponseRewrite and you'll find it does not work any more... :-( – Louis Somers May 20 '12 at 22:06
  • 2
    @LouisSomers Since this answer, I have found the better way is the one described in this question: http://stackoverflow.com/questions/1171035/asp-net-mvc-custom-error-handling-application-error-global-asax I prefer not to redirect the user to a different URL because it is less user-friendly (even I find it annoying while developing). Cheers. – smdrager May 21 '12 at 00:52
  • I'm getting the error `Config Error: The configuration section 'customErrors' cannot be read because it is missing a section declaration`. – alex Feb 16 '17 at 18:28
7

Also you can handle NOT FOUND error in Global.asax.cs as below

protected void Application_Error(object sender, EventArgs e)
{
    Exception lastErrorInfo = Server.GetLastError();
    Exception errorInfo = null;

    bool isNotFound = false;
    if (lastErrorInfo != null)
    {
        errorInfo = lastErrorInfo.GetBaseException();
        var error = errorInfo as HttpException;
        if (error != null)
            isNotFound = error.GetHttpCode() == (int)HttpStatusCode.NotFound;
    }
    if (isNotFound)
    {
        Server.ClearError();
        Response.Redirect("~/Error/NotFound");// Do what you need to render in view
    }
}
bob0the0mighty
  • 782
  • 11
  • 28
MSDs
  • 73
  • 1
  • 4
4

Add this lines under your project root web.config File.

 <system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404" />
  <error statusCode="404" responseMode="ExecuteURL" path="/Test/PageNotFound" />
  <remove statusCode="500" />
  <error statusCode="500" responseMode="ExecuteURL" path="/Test/PageNotFound" />
</httpErrors>
<modules>
  <remove name="FormsAuthentication" />
</modules>

Vicky
  • 819
  • 2
  • 13
  • 30
  • Thank you this is what I needed. In case anyone falls into the same issue as me existingResponse="Replace" fixed it. I had Auto set in there before which is the suggested option in most posts. I guess auto in my case scenario was not able to determine to use replace. – Dimitar Dyankov Apr 19 '18 at 15:06
3

This might be a problem when you use

throw new HttpException(404);

When you want to catch that, I don't know any other way then editing your web config.

Paco
  • 8,335
  • 3
  • 30
  • 41
  • ActionFilters : use them to catch the HttpException. – Pure.Krome Nov 23 '08 at 03:04
  • What if the exception is not thrown by a controller action? I throw a 404 in my controller factory. – Paco Nov 23 '08 at 13:38
  • Not sure then - i'm not playing around with controller factories. soz. – Pure.Krome Apr 09 '09 at 14:59
  • 1
    Controllerfactory is not the only place where it can happen. I map a catch all route to an actionmethod that just throws the exception. The exception is handled by the web.config – Paco Apr 09 '09 at 17:52
  • Throw any `Exception` you want. Let all your controller derived from a `BaseController`. In this `BaseController` you override `OnException` and set the filterContext.Result either redirect or view result. – CallMeLaNN May 19 '11 at 08:25
1

An alternative to creating a catch-all route is to add an Application_EndRequest method to your MvcApplication per Marco's Better-Than-Unicorns MVC 404 Answer.

Community
  • 1
  • 1
Edward Brey
  • 40,302
  • 20
  • 199
  • 253
1

Inside RouterConfig.cs add the follwing piece of code:

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

           });
Jevgeni Geurtsen
  • 3,133
  • 4
  • 17
  • 35
0

If the route cannot be resolved, then MVC framework will through 404 error.. Best approach is to use Exception Filters ... Create a custom exceptionfilter and make like this..

public class RouteNotFoundAttribute : FilterAttribute, IExceptionFilter {
    public void OnException(ExceptionContext filterContext) {
        filterContext.Result  = new RedirectResult("~/Content/RouteNotFound.html");
   }
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402