使用ASP.NET MVC处理全局和HTTP异常

时间:2018-09-26 07:17:48

标签: asp.net-mvc asp.net-mvc-5

我正在尝试使用Global.asax文件中的Application_Error()事件在Asp.Net MVC中使用自定义错误页面和正确的HTTP状态代码来处理global(StatusCode 500)和http异常。实际上,为了简单起见,对于所有类型的已处理异常,我只有相同的视图错误。

现在的问题是,当处理了500个异常时,它将在Application_Error的else节中第一次运行,然后返回到if节,最后返回404 http异常而不是500个异常。

当处理500个异常时,如何通过在Application_Error的else部分中停止运行来解决此问题?

这是我的配置: web.config

<system.web>
   <customErrors mode="Off"/>
</system.web>

 <system.webServer>
      <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="400"/>
        <remove statusCode="401"/>
        <remove statusCode="403"/>
        <remove statusCode="404"/>
        <remove statusCode="500"/>
        <error statusCode="400" responseMode="ExecuteURL" path="/Error"/>
        <error statusCode="401" responseMode="ExecuteURL" path="/Error"/>
        <error statusCode="403" responseMode="ExecuteURL" path="/Error"/>
        <error statusCode="404" responseMode="ExecuteURL" path="/Error"/>
        <error statusCode="500" responseMode="ExecuteURL" path="/Error"/>
      </httpErrors>
</system.webServer>

方法Application_Error():

public void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
        HttpException httpException = exception as HttpException;

        // Clear the response stream
        HttpContext httpContext = ((HttpApplication)sender).Context;
        httpContext.Response.Clear();
        httpContext.ClearError();

        var routeData = new RouteData();
        routeData.Values.Add("controller", "Error");
        routeData.Values.Add("action", "Error");
        routeData.Values.Add("exception", exception);


        if (exception.GetType() == typeof(HttpException)) //It's an Http Exception
        {
            routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());

            switch (routeData.Values["statusCode"])
            {
                case 400:
                    routeData.Values.Add("status", "400 - Bad Request");
                    break;
                case 401:
                    routeData.Values.Add("status", "401 - Access Denied");
                    break;
                case 403:
                    routeData.Values.Add("status", "403 - Forbidden");
                    break;
                case 404:
                    routeData.Values.Add("status", "404 - Page Not Found");
                    break;
                case 500:
                default:
                    routeData.Values.Add("status", "500 - Internal Server Error");
                    break;
            }
        }
        else
        {
            routeData.Values.Add("statusCode", 500);
            routeData.Values.Add("status", "500 - Internal Server Error");

        }

        // Avoid IIS7 getting in the middle
        httpContext.Response.TrySkipIisCustomErrors = true;

        // Call target Controller and pass the routeData.
        IController controller = new ErrorController();
        controller.Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
        Response.End();
        // clear error on server
        //Server.ClearError();
    }

Controller ErrorController:

public class ErrorController : Controller
    {
        // GET: /Error/
        public ActionResult Error(int statusCode, string status, Exception exception)
        {
            Response.StatusCode = statusCode;
            ViewBag.StatusCode = statusCode;
            ViewBag.Status = status;
            return View();
        }
    }

1 个答案:

答案 0 :(得分:0)

其背后的原因是,应用程序引发的Exception的类型并不总是HttpException。可能是SQLException, SystemException, IndexOutOfRangeException等。状态代码始终仅与HttpExceptions关联。这就是为什么您的代码首先进入else部分,然后进入if部分的原因。

尽管它不应再次出现在if部分,但是如果即将出现,则必须检查要重定向的页面是否没有引发其他异常。

我还建议您从代码中删除最后一个参数,因为Exception是一种复杂类型,并且我们通常不会在Get请求中传递复杂类型。

转换

public ActionResult Error(int statusCode, string status, Exception exception)

public ActionResult Error(int statusCode, string status)