.NET MVC global exception handling (1)

Posted Jun 16, 20205 min read

I have always known that there are related configurations for .NET, but I have not actually done it. I think it is okay to change the settings. As a result, I still encounter many problems when I actually use it, so I need to record it.

IIS configuration

At first I didn't want to change the program code, so I immediately thought of the error page configuration configuration in IIS. At the beginning, I repeatedly tested and changed the settings a lot, but it has no effect. It was later found that the configuration of the static page has not entered the MVC program part. So for .NET MVC such dynamic pages are not effective, you should use the .NET error page option

Static error page configuration

The static page configuration process is as follows:



As shown in the above figure, there are three ways to configure the response to errors in IIS. The default is the third. Local access displays detailed error information, and external address access displays a custom page, which is convenient for developers to debug. If no specific errors are set The page will use the style that comes with IIS, which is the configuration in the second picture. According to the path, we can find such a folder, which is a static page with error prompts, corresponding to different status codes.

We can set IIS to use custom error pages to see the effect, or directly through the file access


The one above is a detailed static 404 error, you can see that it will expose our system path, and the following is the default custom error page

The default page of the static error has corresponding settings, which can be modified. There are three types of "file", "execution URL", and "redirect", but the actual setting will find an error:locking error

Through this error, we searched for solutions to see that some people said that the defaultPath under the httperror section in web.config can be unlocked, but it seems that this is the previous setting of IIS7. There is no corresponding option in IIS10. See some The description mentioned that it may be that the official uses a more secure management mechanism, because it is found that the configuration here is related to static pages, which does not meet my needs, and there is no in-depth research. If you must use this, you can check this blog and try Is it possible to solve the locking problem through system commands

win7 IIS Web.config node lock problem

.NET error page configuration

The settings of the .NET error page are similar to the static page, except that the entry is different, and the configuration options are not the same, but the overall meaning is the same.


It can be seen that the requirement here is an absolute URL, so it should be inconvenient to use it in practice, so I did not find much relevant information. In addition, the customError in web.conig needs to be set to On, and some exceptions such as 500 will automatically jump to the default error page of MVC Home/Error

Although there is no need to change the code for error page processing using IIS, it has many limitations in maintenance. In the end, the global exception should be captured through the program.

Program settings

I think of two methods of program control, one is to use the Application_Error method in the global configuration file Global.asax, and the other is to use the MVC filter. The default four filters include exception filtering

Global exception configuration

This method is common to both WebForm and MVC. In ASP.NET, as long as the website program throws an uncaught exception, the Application_Error event will be triggered.

To use this method, you must cancel the HandleErrorAttribute registration in the GlobalFilter global filter, or you can turn off the customErrors node in the configuration file, otherwise HTTP 500 errors will not be caught by the Application_Error event.


After catching the exception, we can easily jump to the static page

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    var httpStatusCode =(exception as HttpException)?.GetHttpCode() ?? 700; //If it is empty, go to customize
    var httpContext =((MvcApplication)sender).Context;
    httpContext.ClearError();

    switch(httpStatusCode)
    {
        case 404:
            httpContext.Response.Redirect("~/Error/404.htm");
            break;
        default:
            httpContext.Response.Redirect("~/Error/500.htm");
            break;
    }
}

In general, we can also point to a controller

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    var httpStatusCode =(exception as HttpException)?.GetHttpCode() ?? 700; //If it is empty, go to customize
    var httpContext =((MvcApplication)sender).Context;
    httpContext.ClearError();

    var routeDic = new RouteValueDictionary
    {
        {"controller", "Home"},
        {"action","Error"}
    };
    httpContext.Response.RedirectToRoute("Default", routeDic);
}

However, in the actual business, I encountered some problems with http requests. When handling exceptions thrown by some codes, a series of exceptions such as "the server cannot send HTTP headers after being sent..." "State", "append header", etc., this time jump to use another way of writing

protected void Application_Error(object sender, EventArgs e)
{
    Server.ClearError();
    Response.TrySkipIisCustomErrors = true;
    var routeData = new RouteData();
    IController controller = new HomeController();
    routeData.Values.Add("controller", "Home");
    routeData.Values.Add("action", "Error");
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();
}

One thing to note here is that if you want to use the controller in Area, you can not write routeData.Values.Add, but use DataTokens

routeData.DataTokens.Add("area", "TestArea");