2012-02-27 98 views
10

我有一个自定义HandleError属性,处理MVC管道上的错误;我在我的Global.asax上有一个protected void Application_Error(object sender, EventArgs e)方法,它处理来自管道外部的错误。ASP.NET MVC全局错误处理

我遇到了一个我不知道的情景;在实施DI时,connectionString的依赖关系取自应用程序配置文件。

由于连接字符串尚不存在,所以在创建控制器时会引发错误,这通常会导致Application_Error处理程序触发,并且呈现适当的错误页面(通过将部分视图呈现为字符串并将其作为“致命异常”。对此,并且如果失败,它只是写入响应

除了在这种情况下,我得到的fugly默认ASP.NET“运行时错误”死亡黄屏告诉我:

运行时错误

说明:在 服务器上发生应用程序错误。此应用程序的当前自定义错误设置阻止 查看应用程序错误的详细信息。

详细信息:若要使此特定错误信息的细节是 可见的本地服务器计算机上,请在位于当前Web应用程序的根目录 的“web.config”配置文件中创建一个 标签。该标签 应该将其“模式”属性设置为“RemoteOnly”。要启用 可以在远程计算机上查看详细信息,请将“模式”设置为 “关闭”。

我没有defaultRedirect集我customErrors,也不是原来Off,因为我不想重定向,而是呈现相同页面的用户是在错误,避免不必要的重定向。

我该如何处理这种情况?甚至为什么它以这种方式行事,而不是像控制器之外的任何其他错误?

我意识到这不太可能经常发生,但我希望能够阻止YSOD(部分原因是因为我想隐藏我正在使用的技术,但主要是因为它不是很漂亮,也不是用户友好的)

我甚至尝试注册UnhandledExceptions的处理程序,但它也没有触发。

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 

最终产生这种情况的代码,是:

return ConfigurationManager.ConnectionStrings[key].ConnectionString;,其中ConnectionStrings[key]null

更新

这就是广告应用程式错误的处理:

protected void Application_Error(object sender, EventArgs e) 
    { 
     this.HandleApplicationError(new ResourceController()); 
    } 

    public static void HandleApplicationError(this HttpApplication application, BaseController controller) 
    { 
     if (application == null) 
     { 
      throw new ArgumentNullException("application"); 
     } 
     if (controller == null) 
     { 
      throw new ArgumentNullException("controller"); 
     } 
     application.Response.Clear(); 
     Exception exception = application.Server.GetLastError(); 
     LogApplicationException(application.Response, exception); 
     try 
     { 
      RenderExceptionViewResponse(application, exception, controller); 
     } 
     catch (Exception exceptionRenderingView) // now we're in trouble. let's be as graceful as possible. 
     { 
      RenderExceptionTextResponse(application, exceptionRenderingView); 
     } 
     finally 
     { 
      application.Server.ClearError(); 
     } 
    } 

    private static void LogApplicationException(HttpResponse response, Exception exception) 
    { 
     if (exception is HttpException) 
     { 
      HttpException httpException = (HttpException)exception; 
      if (httpException.GetHttpCode() == (int)HttpStatusCode.NotFound) 
      { 
       _log.Debug(Resources.Error.WebResourceNotFound, httpException); 
       response.Status = Resources.Constants.NotFound; 
       return; 
      } 
     } 
     _log.Error(Resources.Error.UnhandledException, exception); 
    } 

    private static void RenderExceptionViewResponse(HttpApplication application, Exception exception, BaseController controller) 
    { 
     if (!RenderAsJsonResponse(application, Resources.User.UnhandledExceptionJson)) 
     { 
      ErrorViewModel model = WebUtility.GetErrorViewModel(exception); 
      string result = controller.RenderViewToString(Resources.Constants.ErrorViewName, model); 
      application.Response.Write(result); 
     } 
    } 

    private static void RenderExceptionTextResponse(HttpApplication application, Exception exceptionRenderingView) 
    { 
     application.Response.Clear(); 

     if (!RenderAsJsonResponse(application, Resources.User.FatalExceptionJson)) 
     { 
      application.Response.Write(Resources.User.FatalException); 
     } 
     _log.Fatal(Resources.Error.FatalException, exceptionRenderingView); 
    } 

    private static bool RenderAsJsonResponse(HttpApplication application, string message) 
    { 
     if (application.Request.IsAjaxRequest()) 
     { 
      application.Response.Status = Resources.Constants.HttpSuccess; 
      application.Response.ContentType = Resources.Constants.JsonContentType; 
      application.Response.Write(message); 
      return true; 
     } 
     return false; 
    } 

这是我用它来装饰我的基本控制器属性:

public class ErrorHandlingAttribute : HandleErrorAttribute 
{ 
    public Type LoggerType { get; set; } 

    public ErrorHandlingAttribute() 
     : this(typeof(ErrorHandlingAttribute)) 
    { 
    } 

    public ErrorHandlingAttribute(Type loggerType) 
    { 
     LoggerType = loggerType; 
    } 

    public override void OnException(ExceptionContext filterContext) 
    { 
     if (filterContext.ExceptionHandled) 
     { 
      return; 
     } 
     if (filterContext.HttpContext.Request.IsAjaxRequest()) 
     { 
      OnAjaxException(filterContext); 
     } 
     else 
     { 
      OnRegularException(filterContext); 
     } 
    } 

    internal protected void OnRegularException(ExceptionContext filterContext) 
    { 
     Exception exception = filterContext.Exception; 

     ILog logger = LogManager.GetLogger(LoggerType); 
     logger.Error(Resources.Error.UnhandledException, exception); 

     filterContext.HttpContext.Response.Clear(); 

     ErrorViewModel model = WebUtility.GetErrorViewModel(exception); 
     filterContext.Result = new ViewResult 
     { 
      ViewName = Resources.Constants.ErrorViewName, 
      ViewData = new ViewDataDictionary(model) 
     }; 
     filterContext.ExceptionHandled = true; 
    } 

    internal protected void OnAjaxException(ExceptionContext filterContext) 
    { 
     Exception exception = filterContext.Exception; 

     ILog logger = LogManager.GetLogger(LoggerType); 
     logger.Error(Resources.Error.UnhandledAjaxException, exception); 

     filterContext.HttpContext.Response.Clear(); 
     filterContext.HttpContext.Response.Status = Resources.Constants.HttpSuccess; 

     string errorMessage = WebUtility.GetUserExceptionMessage(exception, true); 

     filterContext.Result = new ExceptionJsonResult(new[] { errorMessage }); 
     filterContext.ExceptionHandled = true; 
    } 
} 

这是我customErrors

<customErrors mode="On" /> 

正如你可以看到这些是相当广泛的,但是他们甚至不访问ConnectionStrings的情况下,其中ConnectionString不存在;这有点令人费解。

确实在任何控制器中包含的异常或异常不在控制器内,所以我不明白为什么这种情况有什么不同。

回答

0

您还没有表现出究竟是你在你的Application_Error事件处理中的错误,也没有如何做您的自定义HandleAttribute实现,所以很难猜测的问题可能是什么。在实现Application_Error时需要注意的一个常见问题是,您会渲染一些错误视图,它本身会引发错误。例如,考虑一个依赖于布局的错误视图,在此布局中,您要调用Html.Action帮助程序来渲染另一个操作的内容,该操作本身会执行数据库访问和内容。您的错误视图应尽可能静态。理想情况下,你应该有一个不同的布局,以避免这种情况。

我也建议你考虑看看following approach处理错误。

+0

我和我的错误处理配置更新。 – bevacqua 2012-02-27 16:24:26

+0

使用PartialView怎么样?你可以看看[全局错误处理在MVC中使用PartialView](http://stackoverflow.com/questions/39594409/global-error-handling-using-partialview-in-mvc)? – 2016-09-20 12:46:07

7

Application_Error可能是处理中的ASP.NET WebForms的错误的推荐方式。但不是在MVC中。

我们得到了照顾误差为我们的错误过滤器。过滤器的问题在于它只在调用控制器时才起作用。 404和401错误(未找到和授权)和数据库连接问题是哪个问题。

customErrors是去这里的路。我不明白为什么重定向应该是一个问题?

我会通过适当的错误处理在博客文章:http://blog.gauffin.org/2011/11/how-to-handle-errors-in-asp-net-mvc/

+8

自定义错误的重定向是一个问题,因为它基本上向浏览器(或机器人)返回缺少的页面“这个页面没问题,但现在请访问这个页面”,然后下一页显示“不是我”我不行,我不存在“。然而,您的浏览器和机器人(例如谷歌机器人)会将缺少的页面存储为真实页面,并继续尝试在谷歌的情况下对其进行索引,因为临时重定向表示将来会继续检查原始页面。这就是为什么在请求的原始URL上返回状态404非常重要。 – 2012-08-10 23:14:23

+0

@jgauffin当偏好使用** PartialView **进行错误和异常处理时,重定向也是一个问题。你可以看看[全局错误处理在MVC中使用PartialView](http://stackoverflow.com/questions/39594409/global-error-handling-using-partialview-in-mvc)? – 2016-09-20 12:45:44

0

是正确的,以我们的访客和搜索引擎,我们应该返回有意义的HTTP状态代码,如果发生错误,面对我们的网站。即使在我们返回视图的同时,返回错误发生时的错误也是不公平的,即使我们在返回视图的同时也解释错误发生了。如果用户输入了错误的地址(最常见的用户错误),我们应该返回HTTP状态码404,而不是返回或重定向到一个视图,其中将返回状态码200。
有一个简短而干净的建议摘要HERE