How to make custom error pages work in ASP.NET MVC 4
我想要显示500,404和403的自定义错误页面。这是我所做的:
在web.config中启用了自定义错误,如下所示:
1 2 3 4 5 6 7 8 9 10 | <customErrors mode="On" defaultRedirect="~/Views/Shared/Error.cshtml"> <error statusCode="403" redirect="~/Views/Shared/UnauthorizedAccess.cshtml" /> <error statusCode="404" redirect="~/Views/Shared/FileNotFound.cshtml" /> </customErrors> |
将
1 2 3 4 5 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomHandleErrorAttribute()); filters.Add(new AuthorizeAttribute()); } |
为上述每条消息创建了自定义错误页面。 500的默认值已经开箱即用。
在每个自定义错误页面视图中声明该页面的模型是
对于500,它显示自定义错误页面。 对于其他人,它没有。
有什么我想念的吗?
看起来这并不是显示自定义错误的全部,因为我在
我该怎么做才能处理其他错误?
我当前的设置(在MVC3上,但我认为它仍然适用)依赖于
1 2 3 4 5 | <system.web> <customErrors mode="On" defaultRedirect="~/Error"> <error redirect="~/Error/NotFound" statusCode="404" /> </customErrors> </system.web> |
控制器包含以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 | public class ErrorController : Controller { public ViewResult Index() { return View("Error"); } public ViewResult NotFound() { Response.StatusCode = 404; //you may want to set this to 200 return View("NotFound"); } } |
视图就是你实现它们的方式。我倾向于添加一些逻辑,以显示应用程序处于调试模式时的堆栈跟踪和错误信息。所以Error.cshtml看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @model System.Web.Mvc.HandleErrorInfo @{ Layout ="_Layout.cshtml"; ViewBag.Title ="Error"; } <span>Error</span> An unexpected error has occurred. Please contact the system administrator. @if (Model != null && HttpContext.Current.IsDebuggingEnabled) { <p> Exception: @Model.Exception.Message<br /> Controller: @Model.ControllerName<br /> Action: @Model.ActionName </p> [cc] @Model.Exception.StackTrace |
}
代码> PRE>
我已经完成了pablo解决方案而且我总是遇到错误(MVC4)
The view 'Error' or its master was not found or no view engine supports the searched location.
要摆脱这一点,删除该行
1 | filters.Add(new HandleErrorAttribute()); |
在FilterConfig.cs中
我做的事情需要的代码少于发布的其他解决方案。
首先,在我的web.config中,我有以下内容:
1 2 3 4 | <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors> |
控制器(/Controllers/ErrorPageController.cs)包含以下内容:
1 2 3 4 5 6 7 8 9 | public class ErrorPageController : Controller { public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } |
最后,视图包含以下内容(为简单起见,它被删除,但它可以包含:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | @{ ViewBag.Title ="Oops! Error Encountered"; } <section id="Page"> <table cellspacing="5" cellpadding="3" style="background-color:#fff;width:100%;" class="table-responsive"> <tbody> <tr> <td valign="top" align="left" id="tableProps"> <img width="25" height="33" src="~/Images/PageError.gif" id="pagerrorImg"> </td> <td width="360" valign="middle" align="left" id="tableProps2"> <h1 style="COLOR: black; FONT: 13pt/15pt verdana" id="errortype"><span id="errorText">@Response.Status</span> </td> </tr> <tr> <td width="400" colspan="2" id="tablePropsWidth"><font style="COLOR: black; FONT: 8pt/11pt verdana">Possible causes:</font> </td> </tr> <tr> <td width="400" colspan="2" id="tablePropsWidth2"> <font style="COLOR: black; FONT: 8pt/11pt verdana" id="LID1"> <ul> <li id="list1"> <span class="infotext"> Baptist explanation: There must be sin in your life. Everyone else opened it fine. </span> </li> <li> <span class="infotext"> Presbyterian explanation: It's not God's will for you to open this link. </span> </li> <li> <span class="infotext"> Word of Faith explanation: You lack the faith to open this link. Your negative words have prevented you from realizing this link's fulfillment. </span> </li> <li> <span class="infotext"> Charismatic explanation: Thou art loosed! Be commanded to OPEN! </span> </li> <li> <span class="infotext"> Unitarian explanation: All links are equal, so if this link doesn't work for you, feel free to experiment with other links that might bring you joy and fulfillment. </span> </li> <li> <span class="infotext"> Buddhist explanation: ......................... </span> </li> <li> <span class="infotext"> Episcopalian explanation: Are you saying you have something against homosexuals? </span> </li> <li> <span class="infotext"> Christian Science explanation: There really is no link. </span> </li> <li> <span class="infotext"> Atheist explanation: The only reason you think this link exists is because you needed to invent it. </span> </li> <li> <span class="infotext"> Church counselor's explanation: And what did you feel when the link would not open? </span> </li> </ul> <p> </p> <h2 style="font:8pt/11pt verdana; color:black" id="ietext"> <img width="16" height="16" align="top" src="~/Images/Search.gif"> HTTP @Response.StatusCode - @Response.StatusDescription </font> </td> </tr> </tbody> </table> </section> |
就这么简单。它可以很容易地扩展,以提供更详细的错误信息,但ELMAH为我处理,statusCode和statusDescription是我通常需要的。
我建议使用Global.asax.cs文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | protected void Application_Error(Object sender, EventArgs e) { var exception = Server.GetLastError(); if (exception is HttpUnhandledException) { Server.Transfer("~/Error.aspx"); } if (exception != null) { Server.Transfer("~/Error.aspx"); } try { // This is to stop a problem where we were seeing"gibberish" in the // chrome and firefox browsers HttpApplication app = sender as HttpApplication; app.Response.Filter = null; } catch { } } |
这里似乎有许多步骤混杂在一起。我会提出我从头开始做的事情。
创建
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class ErrorPageController : Controller { public ActionResult Index() { return View(); } public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } |
添加这两个操作的视图(右键单击 - >添加视图)。这些应出现在名为ErrorPage的文件夹中。
在
1 2 3 4 5 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // Remove this filter because we want to handle errors ourselves via the ErrorPage controller //filters.Add(new HandleErrorAttribute()); } |
在web.config中,在
1 2 3 4 | <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors> |
测试(当然)。在代码中抛出未处理的异常并看到它转到ID为500的页面,然后使用URL到不存在的页面以查看404。
在maxspan发布的答案的基础上,我在GitHub上整理了一个最小的示例项目,展示了所有工作部分。
基本上,我们只是在global.asax.cs中添加一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | protected void Application_Error(Object sender, EventArgs e) { // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4 // for additional context on use of this technique var exception = Server.GetLastError(); if (exception != null) { // This would be a good place to log any relevant details about the exception. // Since we are going to pass exception information to our error page via querystring, // it will only be practical to issue a short message. Further detail would have to be logged somewhere. // This will invoke our error page, passing the exception message via querystring parameter // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above. // As an alternative, Response.Redirect could be used instead. // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 ) Server.TransferRequest("~/Error?Message=" + exception.Message); } } |
错误控制器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /// <summary> /// This controller exists to provide the error page /// </summary> public class ErrorController : Controller { /// <summary> /// This action represents the error page /// </summary> /// <param name="Message">Error message to be displayed (provided via querystring parameter - a design choice)</param> /// <returns></returns> public ActionResult Index(string Message) { // We choose to use the ViewBag to communicate the error message to the view ViewBag.Message = Message; return View(); } } |
错误页面查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!DOCTYPE html> <html> <head> Error </head> <body> My Error <p> @ViewBag.Message </p> </body> </html> |
除了在FilterConfig.cs中禁用/删除
1 2 3 4 5 6 7 | public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); // <== disable/remove } } |
虽然实现起来非常简单,但我在这种方法中看到的一个缺点是使用查询字符串将异常信息传递到目标错误页面。
我已经完成了所有设置,但仍然无法在我们的登台服务器上看到状态代码500的正确错误页面,尽管事实上在本地开发服务器上一切正常。
我发现Rick Strahl的这篇博文对我有帮助。
我需要将
这是我的解决方案。在我看来,使用[ExportModelStateToTempData] / [ImportModelStateFromTempData]是不舒服的。
?/查看/主页/ Error.cshtml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @{ ViewBag.Title ="Error"; Layout ="~/Views/Shared/_Layout.cshtml"; } Error <hr/> @Html.ValidationMessage("Error") <br /> <br /> <button onclick="Error_goBack()" class="k-button">Go Back</button> function Error_goBack() { window.history.back() } |
?/控制器/ HomeController.sc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class HomeController : BaseController { public ActionResult Index() { return View(); } public ActionResult Error() { return this.View(); } ... } |
?/控制器/ BaseController.sc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class BaseController : Controller { public BaseController() { } protected override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.Result is ViewResult) { if (filterContext.Controller.TempData.ContainsKey("Error")) { var modelState = filterContext.Controller.TempData["Error"] as ModelState; filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair<string, ModelState>("Error", modelState) }); filterContext.Controller.TempData.Remove("Error"); } } if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) { if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error")) { filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"]; } } base.OnActionExecuted(filterContext); } } |
?/控制器/ MyController.sc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class MyController : BaseController { public ActionResult Index() { return View(); } public ActionResult Details(int id) { if (id != 5) { ModelState.AddModelError("Error","Specified row does not exist."); return RedirectToAction("Error","Home"); } else { return View("Specified row exists."); } } } |
祝你项目成功;-)
您可以在不破坏global.cs的情况下正确地处理错误,弄乱HandleErrorAttribute,执行Response.TrySkipIisCustomErrors,挂钩Application_Error或其他:
在system.web(只是通常,开/关)
1 2 3 4 | <customErrors mode="On"> <error redirect="/error/401" statusCode="401" /> <error redirect="/error/500" statusCode="500" /> </customErrors> |
并在system.webServer中
1 | <httpErrors existingResponse="PassThrough" /> |
现在事情应该按预期运行,您可以使用ErrorController来显示您需要的任何内容。
在web.config中,在system.webserver标记下添加,如下所示,
1 2 3 4 5 6 7 | <system.webServer> <httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404"/> <remove statusCode="500"/> <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound"/> <error statusCode="500" responseMode="ExecuteURL"path="/Error/ErrorPage"/> </httpErrors> |
并添加一个控制器,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class ErrorController : Controller { // // GET: /Error/ [GET("/Error/NotFound")] public ActionResult NotFound() { Response.StatusCode = 404; return View(); } [GET("/Error/ErrorPage")] public ActionResult ErrorPage() { Response.StatusCode = 500; return View(); } } |
并添加他们尊重的视图,这绝对是我猜的所有。
这个解决方案我发现它来自:海王星世纪
我似乎来晚了,但你最好还是检查一下。
所以在
1 2 3 4 5 6 | <system.web> <customErrors mode="RemoteOnly"> <error statusCode="404" redirect="/page-not-found" /> <error statusCode="500" redirect="/internal-server-error" /> </customErrors> </system.web> |
并在
1 2 3 4 5 6 7 | <system.webServer> <httpErrors errorMode="DetailedLocalOnly"> <remove statusCode="404"/> <error statusCode="404" path="/page-not-found" responseMode="Redirect"/> <remove statusCode="500"/> <error statusCode="500" path="/internal-server-error" responseMode="Redirect"/> </system.webServer> |
在最后一个如果您担心客户端响应然后将