ASP.NET MVC自定义错误

时间:2013-01-25 23:37:37

标签: c# asp.net asp.net-mvc asp.net-mvc-4

我的目标是在应用程序中创建一个处理所有托管错误的错误处理,而不仅仅是与MVC相关。所以我没有使用HandleErrorAttribute模式,因为它仅用于MVC错误,而不是其他托管错误。

在我的Global.asax中,我有:

protected void Application_Error()
{
    string displayError = ConfigurationManager.AppSettings["DisplayError"];
    NameValueCollection serverVariables;
    int loop1, loop2;
    StringBuilder serverVariableKeys = new StringBuilder();
    Exception exception = Server.GetLastError();
    HttpException httpException = exception as HttpException;

    if (HttpContext.Current != null)
    {
            // loop through and get server vars
    }

    if (exception != null)
        // Log Error

    // Redirect to Error page if set to basic mode
    if (!string.IsNullOrWhiteSpace(displayError) && displayError.ToLower() == "basic")
    {
        Response.Clear();
    Server.ClearError(); // needed for redirect to work

    var routeData = new RouteData();
    routeData.Values["controller"] = "Error";
    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 Controllers.ErrorController();
    var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
    errorsController.Execute(rc);
    }
}

我的ErrorControllerGeneralHttp403Http404行为。我有与每个动作相对应的视图。

在我的web.config中,我有:

  <system.web>  
    <!-- removed bits to reduce space -->
    <customErrors mode="On" />
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules >
      <remove name="UrlRoutingModule-4.0" />
      <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
      <remove name="Session"/>
      <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition=""/>
    </modules>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    <httpErrors errorMode="Detailed" />
  </system.webServer>

这适用于与托管代码相关的许多方案,但是当IIS接管时,例如错误的静态文件调用(example.com/BadFileName.gif),它将从IIS返回错误,该错误披露服务器详细信息,例如本地文件路径。这是因为web.config中的以下行:

<httpErrors errorMode="Detailed" />

但是当我将errorMode设置为其他值(如Custom)或者只是删除该行时,我的自定义错误处理将停止运行,并且包括托管代码错误在内的所有内容都会返回默认的IIS错误消息。

我已经尝试过很多方法可以让自定义错误在没有这个设置的情况下工作,但没有任何运气,包括:

  • CustomError设为mode="Off"
  • customError下定义错误节点以重定向到我的控制器
  • httpErrors下定义错误节点以重定向到我的控制器

当我逐步调试时,我可以看到对控制器的调用,但最后IIS会发送响应。错误日志记录确实被正确调用Application_Error,因此代码确实允许应用程序处理它到某一点。

申请详情:

  • ASP.NET MVC 4.0
  • 在IIS 7.5(Azure网站预览)上托管

是否有办法不使用<httpErrors errorMode="Detailed" />并使其有效?

2 个答案:

答案 0 :(得分:36)

您看到行为的原因可能是您的Application_Error处理程序被正确调用(并调用您的控制器),但是IIS正在拦截500错误并显示其自己的错误页面。 (虽然你的Application_Error处理程序本身也可能抛出Exception,这是你想要排除的东西)

因为您想要处理所有错误(例如您提到的静态文件错误),您可能无法依赖ASP.NET或ASP.NET MVC为您执行初始错误检测。 并非所有错误都来自您的应用程序!

最好的办法是尽可能地依靠IIS 7.5的错误处理,而不是试图过早介入。让IIS为您执行初始错误检测,这样更容易。

尝试将以下内容放入web.config,替换现有的httpErrors节点: -

<httpErrors errorMode="Custom" existingResponse="Replace">
  <clear />
  <error statusCode="400" responseMode="ExecuteURL" path="/Error" />
  <error statusCode="403" responseMode="ExecuteURL" path="/Error/Forbidden" />
  <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
  <error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>

完全删除customErrors节点。没必要。

请记住并确保您的错误控制器正在设置正确的状态代码: -

public ActionResult Forbidden()
{
    Response.StatusCode = 403;
    return this.View();
}

然后,除了注销Application_Error处理程序之外,您应该能够抛弃所有内容 - 尽管我认为您最好创建自己的HttpModule;在runAllManagedModulesForAllRequests中的模块节点上设置web.config可以帮助您捕获可能会漏掉的错误。

我已经在Azure网站预览上运行了这个设置(虽然我个人使用elmah进行日志记录),并且除了显然因未能解析web.config而导致的任何错误之外,它正在捕获所有内容。

我放了full working example of using httpErrors for custom error pages up on github。您还可以see it live on azure web sites

答案 1 :(得分:0)

如果你想在你的应用程序中处理这个问题,你可以编写自定义处理程序或使用HandleError属性here是一种很好的例子来解决这个问题,而不必使用IIS作为拐杖。因为并非所有IIS主机提供商都允许在服务器级别进行此类自定义,并且IMO是一种不好的方法,因为它在部署时创建了额外的配置。