【问题标题】:Custom error pages on asp.net MVC3asp.net MVC3 上的自定义错误页面
【发布时间】:2011-07-10 18:04:02
【问题描述】:

我正在开发一个 MVC3 基础网站,我正在寻找一种解决方案来处理错误并为每种错误呈现自定义视图。所以想象一下我有一个“错误”控制器,他的主要操作是“索引”(通用错误页面),这个控制器将对用户可能出现的错误有几个操作,比如“Handle500”或“HandleActionNotFound”。

因此网站上可能发生的每一个错误都可能由这个“错误”控制器处理(例如:“控制器”或“操作”未找到、500、404、dbException 等)。

我正在使用站点地图文件来定义网站路径(而不是路线)。

这个问题已经回答了,这是对 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");
    }
}
}

【问题讨论】:

  • web.config 中的设置应该支持什么?大概你不会包含任何 httperrors 设置?
  • forums.asp.net/p/1782402/4894514.aspx/… 有一些不错的提示,例如 IE 不会显示小于 512 字节的错误页面

标签: asp.net-mvc-3 error-handling


【解决方案1】:

我使用的是 MVC 4.5,但遇到了 Darin 的解决方案的问题。注意:达林的解决方案非常好,我用它来提出我的解决方案。 这是我修改后的解决方案:

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

【讨论】:

  • 您在使用 Darin 的解决方案时遇到了什么问题?
  • 您没有描述您遇到的问题,该问题导致了竞争性答案。
【解决方案2】:

我看到您为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 是否为空,因为Application_Start 中的异常仍将使用此方法,尽管不会有活动上下文。

【讨论】:

    【解决方案3】:

    您也可以在 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>
    

    【讨论】:

      【解决方案4】:

      您可以通过实现 Jeff Atwood 的 User Friendly Exception Handling module 并稍微修改 http 状态代码来显示带有正确 http 状态代码的用户友好错误页面。它无需任何重定向即可工作。虽然代码来自 2004(!),但它与 MVC 配合得很好。它可以完全在您的 web.config 中进行配置,根本无需更改 MVC 项目源代码。

      返回原始 HTTP 状态而不是 200 状态所需的修改在 this related forum post 中进行了描述。

      基本上,在 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
      

      【讨论】:

        【解决方案5】:

        这里有更多文章如何使用 MVC http://kitsula.com/Article/MVC-Custom-Error-Pages 创建自定义错误页面。

        【讨论】:

          【解决方案6】:

          这是我如何处理自定义错误的示例。我定义了一个 ErrorsController,其中包含处理不同 HTTP 错误的操作:

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

          【讨论】:

          • 请注意。由于我想在每种情况下(404、500 等)在每个 ActionResult 上呈现一个视图,因此我返回了一个视图。但是,我尝试捕获 Application_Error 内容,如果失败,则会返回静态 HTML 页面。 (如果有人愿意,我可以发布代码)
          • 我无法在 MVC3 上使用此解决方案来渲染剃刀视图。 return View(model) 例如只得到一个空白屏幕。
          • 添加了 TrySkipIisCustomErrors 以修复集成 IIS7 的问题。见stackoverflow.com/questions/1706934/…
          • @ajbeaven, Execute 是在IController 接口中定义的方法。这不可能得到保护。更仔细地查看我的代码:IController errorsController = new ErrorsController(); 并注意我正在调用Execute 方法的errorsController 变量的类型。它的类型是IController,所以绝对没有什么能阻止你调用这个方法。顺便说一句,Execute 在 Controller 类中以及在 MVC 3 中都受到保护,因此在这方面没有任何变化。
          • 通过明确指定响应的内容类型来修复:Response.ContentType = "text/html";
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-02
          • 1970-01-01
          • 2016-11-26
          • 2016-08-18
          • 2014-06-27
          • 1970-01-01
          相关资源
          最近更新 更多