Once and for all what is the best routing approach

2020-06-27 00:23发布

问题:

There are many articles on SO and the web in attempts to handle 404's and exceptions gracefully.

From what I have read the best advice seems to be have a route for 404's like so:

routes.MapRoute(
    "404-PageNotFound",
    "{*url}",
    new { controller = "ErrorController", action = "PageNotFound" }
    );

Then for other errors have the HandleError atribute on the Controller and have CustomErrors turned on in web.config so it goes to the error.cshtml page.

However I have read that if you get a exception that does not set the HTTP code to 500 the HandleError will not work.

Can we finally produce an answer/best practice that handles 404's/Exceptions/ASP.Net errors where we can apply to this to all our projects?

Thanks

回答1:

I use a simple error handling setup. Nice and simple. More info can be found at http://erictopia.com/2010/04/building-a-mvc2-template-part-7-custom-web-errors-and-adding-support-for-elmah/

Install ELMAH and have it handle all the errors.

Next create an Error controller. Add a catch all route like this:

routes.MapRoute(
    "ErrorHandler", // Route name
    "{*path}",      // URL
    new { controller = "Error", action = "Index" }
);

Then in web.config add this section:

<customErrors mode="RemoteOnly" defaultRedirect="/Error/Index">
        <error statusCode="403" redirect="/Error/NoAccess" />
        <error statusCode="404" redirect="/Error/NotFound" />
</customErrors>


回答2:

No need to set up a 404 route. In global asax application start, set up a global filter to catch 404 where the controller exists but not the action, or if an action returns a 404 result.

        filters.Add(new HttpNotFoundFilterAttribute { Order = 99 });

where the filter is an ActionFilterAttribute with this override:

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result !=null && 
            (filterContext.Result.GetType() == typeof(HttpNotFoundResult) )
        {
            //You can transfer to a known route for example
            filterContext.Result = new TransferResult(SomeAction, SomeController);
        }
    }

And also in Application_Error, in case no controller exists:

        Exception ex = Server.GetLastError();
        string uri = null;
        if (Context != null && Context.Request != null)
        {
            uri = Context.Request.Url.AbsoluteUri;
        }

        Exception baseEx = ex.GetBaseException();
         var httpEx = ex as HttpException;

         if ((httpEx != null && httpEx.GetHttpCode()==404) 
              || (uri != null && Context.Response.StatusCode == 404) )
             { /* do what you want. */ 
               //Example: show some known url
               Server.ClearError();
               Server.TransferRequest(transferUrl);
             }

To avoid handling 404 for static resources, you should install SP1 on Windows 7 or windows 2008 R2 to upgrade IIS7 and set in web.config:

...
<modules runAllManagedModulesForAllRequests="false">
...