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

Handle global and HTTP exception with ASP.NET MVC

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

现在的问题是,当处理 500 异常时,它首先进入 Application_Error 的 else 部分,然后返回到 if 部分,最后是 return 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();
    }

控制器错误控制器:

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();
        }
    }

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

虽然它不应该在 if 部分再次出现,但如果它出现,那么您必须检查您重定向用户的页面是否进一步抛出任何其他异常。

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

转换这个

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

public ActionResult Error(int statusCode, string status)