ASP.NET MVC全局error handling

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

我遇到过一个我不知道可能的情景; 在实现DI时,对于connectionString有一个依赖connectionString ,它取自应用程序配置文件。

由于连接字符串尚不存在,因此在创建控制器时会出现错误,这通常会使Application_Error处理程序触发,并呈现正确的错误页面(通过将部分视图呈现为字符串并将其作为响应发送,并在如果失败,只需将“致命exception”写入响应。

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

运行时错误

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

详细信息:要在本地服务器计算机上查看此特定错误消息的详细信息,请在位于当前Web应用程序根目录中的“web.config”配置文件中创建标记。 然后,此标记应将其“mode”属性设置为“RemoteOnly”。 要使详细信息可在远程计算机上查看,请将“mode”设置为“Off”。

我的customErrors中没有设置defaultRedirect ,也没有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

  

正如您所看到的那些非常广泛,但是在访问ConnectionString不存在的ConnectionString的情况下它们甚至不会触发; 这有点令人费解。

触发任何控制器包含的exception或不在控制器内的exception,所以我不明白为什么这种情况有所不同。

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

我们得到了错误filter,可以解决我们的错误。 filter的问题是它只在调用控制器时才有效。 404和401错误(找不到和授权)和数据库连接问题是哪个问题。

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

我正在博客文章中进行适当的error handling: http : //blog.gauffin.org/2011/11/how-to-handle-errors-in-asp-net-mvc/

您还没有显示您在Application_Error事件中处理错误的具体方式,也没有显示您的自定义HandleAttribute是如何实现的,因此很难猜出问题可能是什么。 实现Application_Error时要注意的一个常见问题是,您呈现一些错误视图,该错误视图本身会引发错误。 例如,假设一个依赖于布局的错误视图,在这个布局中,你调用一个Html.Action帮助器来呈现另一个本身进行数据库访问和操作的动作的内容。 您的错误视图应尽可能保持静态。 理想情况下,您应该为它们设置不同的布局,以避免出现这种情况。

我可能还建议您查看以下处理错误的方法。

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