如何使自定义错误页面在ASP.NET MVC 4中工作

我想要一个自定义的错误页面显示为500,404和403.以下是我所做的:

  1. 在web.config中启用自定义错误,如下所示:

    <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> 
  2. 注册HandleErrorAttribute作为FilterConfig类中的全局操作filter,如下所示:

     public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomHandleErrorAttribute()); filters.Add(new AuthorizeAttribute()); } 
  3. 为每个上述消息创build一个自定义错误页面。 500的默认值已经可以使用了。

  4. 在每个自定义错误页面视图中声明该页面的模型是System.Web.Mvc.HandleErrorInfo

对于500,它显示自定义错误页面。 对于其他人来说,它并不是。

有什么我失踪?

它看起来像这样并不是所有的显示自定义错误,当我通过HandleErrorAttribute类的OnException方法中的代码读取,它只处理500。

我需要做些什么来处理其他错误?

我目前的设置(在MVC3,但我认为它仍然适用)依靠有一个ErrorController ,所以我使用:

 <system.web> <customErrors mode="On" defaultRedirect="~/Error"> <error redirect="~/Error/NotFound" statusCode="404" /> </customErrors> </system.web> 

控制器包含以下内容:

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

意见就是你实施的方式。 我倾向于添加一些逻辑,以显示堆栈跟踪和错误信息,如果应用程序处于debugging模式。 所以Error.cshtml看起来像这样:

 @model System.Web.Mvc.HandleErrorInfo @{ Layout = "_Layout.cshtml"; ViewBag.Title = "Error"; } <div class="list-header clearfix"> <span>Error</span> </div> <div class="list-sfs-holder"> <div class="alert alert-error"> An unexpected error has occurred. Please contact the system administrator. </div> @if (Model != null && HttpContext.Current.IsDebuggingEnabled) { <div> <p> <b>Exception:</b> @Model.Exception.Message<br /> <b>Controller:</b> @Model.ControllerName<br /> <b>Action:</b> @Model.ActionName </p> <div style="overflow:scroll"> <pre> @Model.Exception.StackTrace </pre> </div> </div> } </div> 

我做了巴勃罗解决scheme,我总是有错误(MVC4)

没有find“错误”或其主人的视图,或没有视图引擎支持search的位置。

为了摆脱这一点, 删除线

  filters.Add(new HandleErrorAttribute()); 

在FilterConfig.cs中

我做了一些比其他解决scheme更less的代码。

首先,在我的web.config中,我有以下几点:

 <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors> 

控制器(/Controllers/ErrorPageController.cs)包含以下内容:

 public class ErrorPageController : Controller { public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } 

最后,视图包含以下内容(为了简单起见,简单地说,它可以包含:

 @{ ViewBag.Title = "Oops! Error Encountered"; } <section id="Page"> <div class="col-xs-12 well"> <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></h1> </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"> <hr> <ul> <li id="list1"> <span class="infotext"> <strong>Baptist explanation: </strong>There must be sin in your life. Everyone else opened it fine.<br> </span> </li> <li> <span class="infotext"> <strong>Presbyterian explanation: </strong>It's not God's will for you to open this link.<br> </span> </li> <li> <span class="infotext"> <strong> Word of Faith explanation:</strong> You lack the faith to open this link. Your negative words have prevented you from realizing this link's fulfillment.<br> </span> </li> <li> <span class="infotext"> <strong>Charismatic explanation: </strong>Thou art loosed! Be commanded to OPEN!<br> </span> </li> <li> <span class="infotext"> <strong>Unitarian explanation:</strong> 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.<br> </span> </li> <li> <span class="infotext"> <strong>Buddhist explanation:</strong> .........................<br> </span> </li> <li> <span class="infotext"> <strong>Episcopalian explanation:</strong> Are you saying you have something against homosexuals?<br> </span> </li> <li> <span class="infotext"> <strong>Christian Science explanation: </strong>There really is no link.<br> </span> </li> <li> <span class="infotext"> <strong>Atheist explanation: </strong>The only reason you think this link exists is because you needed to invent it.<br> </span> </li> <li> <span class="infotext"> <strong>Church counselor's explanation:</strong> And what did you feel when the link would not open? </span> </li> </ul> <p> <br> </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 <br> </h2> </font> </td> </tr> </tbody> </table> </div> </section> 

我会build议使用Global.asax.cs文件。

  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. 创buildErrorPage控制器

     public class ErrorPageController : Controller { public ActionResult Index() { return View(); } public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } 
  2. 为这两个操作添加视图(右键单击 – >添加视图)。 这些应该出现在名为ErrorPage的文件夹中。

  3. App_Start里面打开FilterConfig.cs并注释掉error handlingfilter。

     public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // Remove this filter because we want to handle errors ourselves via the ErrorPage controller //filters.Add(new HandleErrorAttribute()); } 
  4. 在web.config里添加System.Web下面的<customerErrors>条目

     <customErrors mode="On" defaultRedirect="~/ErrorPage/Oops"> <error redirect="~/ErrorPage/Oops/404" statusCode="404" /> <error redirect="~/ErrorPage/Oops/500" statusCode="500" /> </customErrors> 
  5. testing(当然)。 在你的代码中抛出一个未处理的exception,并看到它转到页面的ID为500,然后使用一个URL到一个不存在的页面来看404。

感谢上面的每个人。 据此得到赞成。

基于maxspan发布的答案,我已经在GitHub上放了一个最小的示例项目,显示了所有的工作部分。

基本上,我们只是将一个Application_Error方法添加到global.asax.cs中以拦截exception,并使我们有机会将(或更正确地说, 传输请求 )redirect到自定义错误页面。

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

错误控制器:

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

错误页面查看:

 <!DOCTYPE html> <html> <head> <title>Error</title> </head> <body> <h2>My Error</h2> <p>@ViewBag.Message</p> </body> </html> 

除了禁用/删除filters.Add(new HandleErrorAttribute()) FilterConfig.cs

 public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); // <== disable/remove } } 

虽然实现起来非常简单,但是我在这种方法中看到的一个缺点是使用querystring将exception信息传递到目标错误页面。

这是我的解决scheme。 在我看来,使用[ExportModelStateToTempData] / [ImportModelStateFromTempData]是不舒服的。

〜/查看/主页/ Error.cshtml:

 @{ ViewBag.Title = "Error"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Error</h2> <hr/> <div style="min-height: 400px;"> @Html.ValidationMessage("Error") <br /> <br /> <button onclick="Error_goBack()" class="k-button">Go Back</button> <script> function Error_goBack() { window.history.back() } </script> </div> 

〜/控制器/ HomeController.sc:

 public class HomeController : BaseController { public ActionResult Index() { return View(); } public ActionResult Error() { return this.View(); } ... } 

〜/控制器/ BaseController.sc:

 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:

 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(只是通常的,开/关)

 <customErrors mode="On"> <error redirect="/error/401" statusCode="401" /> <error redirect="/error/500" statusCode="500" /> </customErrors> 

并在system.webServer

 <httpErrors existingResponse="PassThrough" /> 

现在事情应该像预期的那样,你可以使用你的ErrorController来显示任何你需要的东西。

我已经设置了一切,但仍然看不到我们的登台服务器上状态码500的错误页面,尽pipe事实上在本地开发服务器上一切正常。

我发现Rick Strahl的这篇博客文章对我有所帮助。

我需要添加Response.TrySkipIisCustomErrors = true; 到我的自定义error handling代码。

看来我晚会来晚了,但你最好也检查一下。

所以在system.web中caching应用程序中的exception,如返回HttpNotFound()

  <system.web> <customErrors mode="RemoteOnly"> <error statusCode="404" redirect="/page-not-found" /> <error statusCode="500" redirect="/internal-server-error" /> </customErrors> </system.web> 

并在system.webServer中,以赶上被IIS捕获的错误,并没有前往asp.net框架

  <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> 

在最后一个如果你担心客户端的响应,然后更改responseMode="Redirect"responseMode="File"并提供一个静态HTML文件,因为这将显示一个友好的页面与200响应代码。

在web.config中添加这个在system.webserver标签下面,

 <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> 

并添加一个控制器,

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

并添加他们尊重的观点,这将绝对工作,我想所有。

这个解决scheme,我发现它来自: 海王星世纪