使用 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)
我正在尝试处理 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)