2012-02-27 158 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