How can I properly handle 404 in ASP.NET MVC?

后端 未结 19 3292
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-21 10:14

I am using RC2

Using URL Routing:

routes.MapRoute(
    \"Error\",
     \"{*url}\",
     new { controller = \"Errors\", action = \"N         


        
19条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-11-21 10:26

    Quick Answer / TL;DR

    enter image description here

    For the lazy people out there:

    Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0
    

    Then remove this line from global.asax

    GlobalFilters.Filters.Add(new HandleErrorAttribute());
    

    And this is only for IIS7+ and IIS Express.

    If you're using Cassini .. well .. um .. er.. awkward ... awkward


    Long, explained answer

    I know this has been answered. But the answer is REALLY SIMPLE (cheers to David Fowler and Damian Edwards for really answering this).

    There is no need to do anything custom.

    For ASP.NET MVC3, all the bits and pieces are there.

    Step 1 -> Update your web.config in TWO spots.

    
        
          
        
    

    and

    
        
          
          
          
          
            
    
    ...
    
    ...
    
    

    Now take careful note of the ROUTES I've decided to use. You can use anything, but my routes are

    • /NotFound <- for a 404 not found, error page.
    • /ServerError <- for any other error, include errors that happen in my code. this is a 500 Internal Server Error

    See how the first section in only has one custom entry? The statusCode="404" entry? I've only listed one status code because all other errors, including the 500 Server Error (ie. those pesky error that happens when your code has a bug and crashes the user's request) .. all the other errors are handled by the setting defaultRedirect="/ServerError" .. which says, if you are not a 404 page not found, then please goto the route /ServerError.

    Ok. that's out of the way.. now to my routes listed in global.asax

    Step 2 - Creating the routes in Global.asax

    Here's my full route section..

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});
    
        routes.MapRoute(
            "Error - 404",
            "NotFound",
            new { controller = "Error", action = "NotFound" }
            );
    
        routes.MapRoute(
            "Error - 500",
            "ServerError",
            new { controller = "Error", action = "ServerError"}
            );
    
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new {controller = "Home", action = "Index", id = UrlParameter.Optional}
            );
    }
    

    That lists two ignore routes -> axd's and favicons (ooo! bonus ignore route, for you!) Then (and the order is IMPERATIVE HERE), I have my two explicit error handling routes .. followed by any other routes. In this case, the default one. Of course, I have more, but that's special to my web site. Just make sure the error routes are at the top of the list. Order is imperative.

    Finally, while we are inside our global.asax file, we do NOT globally register the HandleError attribute. No, no, no sir. Nadda. Nope. Nien. Negative. Noooooooooo...

    Remove this line from global.asax

    GlobalFilters.Filters.Add(new HandleErrorAttribute());
    

    Step 3 - Create the controller with the action methods

    Now .. we add a controller with two action methods ...

    public class ErrorController : Controller
    {
        public ActionResult NotFound()
        {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return View();
        }
    
        public ActionResult ServerError()
        {
            Response.StatusCode = (int)HttpStatusCode.InternalServerError;
    
            // Todo: Pass the exception into the view model, which you can make.
            //       That's an exercise, dear reader, for -you-.
            //       In case u want to pass it to the view, if you're admin, etc.
            // if (User.IsAdmin) // <-- I just made that up :) U get the idea...
            // {
            //     var exception = Server.GetLastError();
            //     // etc..
            // }
    
            return View();
        }
    
        // Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
        public ActionResult ThrowError()
        {
            throw new NotImplementedException("Pew ^ Pew");
        }
    }
    

    Ok, lets check this out. First of all, there is NO [HandleError] attribute here. Why? Because the built in ASP.NET framework is already handling errors AND we have specified all the shit we need to do to handle an error :) It's in this method!

    Next, I have the two action methods. Nothing tough there. If u wish to show any exception info, then u can use Server.GetLastError() to get that info.

    Bonus WTF: Yes, I made a third action method, to test error handling.

    Step 4 - Create the Views

    And finally, create two views. Put em in the normal view spot, for this controller.

    enter image description here

    Bonus comments

    • You don't need an Application_Error(object sender, EventArgs e)
    • The above steps all work 100% perfectly with Elmah. Elmah fraking wroxs!

    And that, my friends, should be it.

    Now, congrats for reading this much and have a Unicorn as a prize!

    enter image description here

提交回复
热议问题