在asp.net MVC3上自定义错误页面
我正在开发一个MVC3基地网站,我正在寻找一个解决方案来处理错误和呈现每种错误的自定义视图。 所以想象一下,我有一个“错误”控制器,他的主要行为是“索引”(通用错误页面),这个控制器将会有更多的动作来处理像“Handle500”或“HandleActionNotFound”这样的错误。
因此,网站上可能发生的每个错误都可以通过这个“错误”控制器来处理(例如:“Controller”或“Action”未找到,500,404,dbException等)。
我正在使用Sitemap文件来定义网站路径(而不是路由)。
这个问题已经回答了,这是对Gweebz的回复
我的最终applicaiton_error方法如下:
protected void Application_Error() { //while my project is running in debug mode if (HttpContext.Current.IsDebuggingEnabled && WebConfigurationManager.AppSettings["EnableCustomErrorPage"].Equals("false")) { Log.Logger.Error("unhandled exception: ", Server.GetLastError()); } else { try { var exception = Server.GetLastError(); Log.Logger.Error("unhandled exception: ", exception); Response.Clear(); Server.ClearError(); var routeData = new RouteData(); routeData.Values["controller"] = "Errors"; routeData.Values["action"] = "General"; routeData.Values["exception"] = exception; IController errorsController = new ErrorsController(); var rc = new RequestContext(new HttpContextWrapper(Context), routeData); errorsController.Execute(rc); } catch (Exception e) { //if Error controller failed for same reason, we will display static HTML error page Log.Logger.Fatal("failed to display error page, fallback to HTML error: ", e); Response.TransmitFile("~/error.html"); } } }
以下是我如何处理自定义错误的示例。 我使用处理不同的HTTP错误的动作来定义一个ErrorsController
:
public class ErrorsController : Controller { public ActionResult General(Exception exception) { return Content("General failure", "text/plain"); } public ActionResult Http404() { return Content("Not found", "text/plain"); } public ActionResult Http403() { return Content("Forbidden", "text/plain"); } }
然后我订阅Global.asax
的Application_Error
并调用此控制器:
protected void Application_Error() { var exception = Server.GetLastError(); var httpException = exception as HttpException; Response.Clear(); Server.ClearError(); var routeData = new RouteData(); routeData.Values["controller"] = "Errors"; routeData.Values["action"] = "General"; routeData.Values["exception"] = exception; Response.StatusCode = 500; if (httpException != null) { Response.StatusCode = httpException.GetHttpCode(); switch (Response.StatusCode) { case 403: routeData.Values["action"] = "Http403"; break; case 404: routeData.Values["action"] = "Http404"; break; } } IController errorsController = new ErrorsController(); var rc = new RequestContext(new HttpContextWrapper(Context), routeData); errorsController.Execute(rc); }
这里是更多的文章如何使用MVC创建自定义错误页面http://kitsula.com/Article/MVC-Custom-Error-Pages 。
您也可以在Web.Config文件中执行此操作。 这里是一个在IIS 7.5中工作的例子。
<system.webServer> <httpErrors errorMode="DetailedLocalOnly" defaultResponseMode="File"> <remove statusCode="502" subStatusCode="-1" /> <remove statusCode="501" subStatusCode="-1" /> <remove statusCode="412" subStatusCode="-1" /> <remove statusCode="406" subStatusCode="-1" /> <remove statusCode="405" subStatusCode="-1" /> <remove statusCode="404" subStatusCode="-1" /> <remove statusCode="403" subStatusCode="-1" /> <remove statusCode="401" subStatusCode="-1" /> <remove statusCode="500" subStatusCode="-1" /> <error statusCode="500" path="/notfound.html" responseMode="ExecuteURL" /> <error statusCode="401" prefixLanguageFilePath="" path="/500.html" responseMode="ExecuteURL" /> <error statusCode="403" prefixLanguageFilePath="" path="/403.html" responseMode="ExecuteURL" /> <error statusCode="404" prefixLanguageFilePath="" path="/404.html" responseMode="ExecuteURL" /> <error statusCode="405" prefixLanguageFilePath="" path="/405.html" responseMode="ExecuteURL" /> <error statusCode="406" prefixLanguageFilePath="" path="/406.html" responseMode="ExecuteURL" /> <error statusCode="412" prefixLanguageFilePath="" path="/412.html" responseMode="ExecuteURL" /> <error statusCode="501" prefixLanguageFilePath="" path="/501.html" responseMode="ExecuteURL" /> <error statusCode="502" prefixLanguageFilePath="" path="/genericerror.html" responseMode="ExecuteURL" /> </httpErrors> </system.webServer>
我看到您为EnableCustomErrorPage
添加了一个配置值,并且您还正在检查IsDebuggingEnabled
以确定是否运行错误处理。
由于在ASP.NET中已经有一个<customErrors/>
配置(正是为了这个目的),最简单的说法就是:
protected void Application_Error() { if (HttpContext.Current == null) { // errors in Application_Start will end up here } else if (HttpContext.Current.IsCustomErrorEnabled) { // custom exception handling } }
然后在配置中,你会把<customErrors mode="RemoteOnly" />
这样安全的部署起来,当你需要测试你的自定义错误页面时,你将它设置为<customErrors mode="On" />
所以你可以验证它的工作。
请注意,您还需要检查HttpContext.Current
是否为null,因为Application_Start
的异常仍会使用此方法,尽管不会有活动的上下文。
您可以通过实施Jeff Atwood的用户友好异常处理模块并稍微修改http状态码来显示带有正确http状态码的用户友好错误页面。 它工作没有任何重定向。 虽然代码是从2004年(!),它适用于MVC。 它可以完全在你的web.config中配置,根本没有MVC项目源代码的变化。
在这个相关的论坛帖子中描述了返回原始HTTP状态而不是200
状态所需的修改。
基本上,在Handler.vb中,可以添加如下内容:
' In the header... Private _exHttpEx As HttpException = Nothing ' At the top of Public Sub HandleException(ByVal ex As Exception)... HttpContext.Current.Response.StatusCode = 500 If TypeOf ex Is HttpException Then _exHttpEx = CType(ex, HttpException) HttpContext.Current.Response.StatusCode = _exHttpEx.GetHttpCode() End If
我正在使用MVC 4.5,并且遇到了达林解决方案的问题。 注意:达林的解决方案非常好,我用它来提出我的解决方案。 这是我的修改解决方案:
protected void Application_Error(object sender, EventArgs e) { var exception = Server.GetLastError(); var httpException = exception as HttpException; Response.StatusCode = httpException.GetHttpCode(); Response.Clear(); Server.ClearError(); if (httpException != null) { var httpContext = HttpContext.Current; httpContext.RewritePath("/Errors/InternalError", false); // MVC 3 running on IIS 7+ if (HttpRuntime.UsingIntegratedPipeline) { switch (Response.StatusCode) { case 403: httpContext.Server.TransferRequest("/Errors/Http403", true); break; case 404: httpContext.Server.TransferRequest("/Errors/Http404", true); break; default: httpContext.Server.TransferRequest("/Errors/InternalError", true); break; } } else { switch (Response.StatusCode) { case 403: httpContext.RewritePath(string.Format("/Errors/Http403", true)); break; case 404: httpContext.RewritePath(string.Format("/Errors/Http404", true)); break; default: httpContext.RewritePath(string.Format("/Errors/InternalError", true)); break; } IHttpHandler httpHandler = new MvcHttpHandler(); httpHandler.ProcessRequest(httpContext); } } }