首页 文章

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

提问于
浏览
224

我想要显示500,404和403的自定义错误页面 . 这是我所做的:

  • 在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>
  • 注册 HandleErrorAttribute 作为 FilterConfig 类中的全局操作过滤器,如下所示:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new CustomHandleErrorAttribute());
    filters.Add(new AuthorizeAttribute());
}
  • 为上述每条消息创建了自定义错误页面 . 500的默认值已经开箱即用 .

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

对于500,它显示自定义错误页面 . 对于其他人,它没有 .

有什么我想念的吗?

当我通读 HandleErrorAttribute 类的 OnException 方法中的代码并且它只处理500时,它看起来并不是显示自定义错误的全部内容 .

我该怎么做才能处理其他错误?

11 回答

  • 0

    我已经完成了所有设置,但仍然无法在我们的登台服务器上看到状态代码500的正确错误页面,尽管事实上在本地开发服务器上一切正常 .

    我发现Rick Strahl的this blog post给了我很多帮助 .

    我需要将 Response.TrySkipIisCustomErrors = true; 添加到我的自定义错误处理代码中 .

  • 2

    我当前的设置(在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");
        }
    }
    

    而观点就是你实现它们的方式 . 我倾向于添加一些逻辑,以显示应用程序处于调试模式时的堆栈跟踪和错误信息 . 所以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
    <b>Controller:</b> @Model.ControllerName
    <b>Action:</b> @Model.ActionName </p> <div style="overflow:scroll"> <pre> @Model.Exception.StackTrace </pre> </div> </div> } </div>
  • 35

    我已经完成了pablo解决方案而且我总是遇到错误(MVC4)

    未找到视图“错误”或其主文件或视图引擎不支持搜索的位置 .

    要摆脱这个, remove the line

    filters.Add(new HandleErrorAttribute());
    

    在FilterConfig.cs中

  • 13

    我做的事情需要的代码少于发布的其他解决方案 .

    首先,在我的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>
    

    就这么简单 . 它可以很容易地扩展,以提供更详细的错误信息,但ELMAH处理对我来说,statusCode和statusDescription是我通常需要的 .

  • 0

    我建议使用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
        {
        }
    }
    
  • 9

    这里似乎有许多步骤混杂在一起 . 我会提出我从头开始做的事情 .

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

    • 内部 App_Start 打开 FilterConfig.cs 并注释掉错误处理过滤器 .

    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内添加以下 <customerErrors> 条目,在 System.Web
    <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 .
  • 6

    在maxspan发布的答案的基础上,我整理了一个显示所有工作部件的最小sample project on GitHub .

    基本上,我们只是将 Application_Error 方法添加到 global.asax.cs 以拦截异常并让我们有机会将(或更准确地说,转移请求)重定向到自定义错误页面 .

    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>
    

    除了在 FilterConfig.cs 中禁用/删除 filters.Add(new HandleErrorAttribute()) 之外,不涉及任何其他内容

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

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

  • 19

    这是我的解决方案 . 在我看来,使用 [ExportModelStateToTempData] / [ImportModelStateFromTempData] 感到很不舒服 .

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

    @{
        ViewBag.Title = "Error";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <h2>Error</h2>
    <hr/>
    
    <div style="min-height: 400px;">
    
        @Html.ValidationMessage("Error")
    
        

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

    祝你项目成功;-)

  • 324

    您可以在不破坏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来显示您需要的任何内容 .

  • 0

    我似乎来晚了,但你最好还是检查一下 .

    所以在 system.web 中进行缓存应用程序中的异常,例如返回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响应代码的友好页面 .

  • 2

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

    并添加他们尊重的视图,这绝对是我猜的所有 .

    我找到了这个解决方案:Neptune Century

相关问题