2012-07-12 58 views
10

當在一個MVC3 web應用我用使用全局日誌

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleErrorAttribute()); 
} 

應用全局錯誤處理,其中用戶被示出的「錯誤」視圖如果未處理的異常出現調用兩次MVC [的HandleError] HandleErrorAttribute。

對於一個特定的視圖,我還希望通過裝飾方法[HandleError(View = "SpecialError")]發生未處理的異常時顯示不同的錯誤視圖。這工作得很好。

我然後想要添加全局日誌記錄未處理的異常。我創建了日誌代碼自定義的HandleError屬性:

public class MyHandleErrorAttribute : HandleErrorAttribute 
    { 
     public override void OnException(ExceptionContext context) 
     { 
      // Write to log code 
      base.OnException(context); 
     } 
    } 

和更新的RegisterGlobalFilters和方法裝飾使用這個屬性名代替。這一般起作用,但是當用MyHandleError(View = "SpecialError")]裝飾的方法內出現異常時,OnException方法被稱爲兩次。我原先假設用這個屬性裝飾方法取代了全局處理器,但它似乎只是被添加到(這更有意義,但它不是我想要的)。通過兩次調用OnException,同樣的異常會被記錄兩次,這是不會發生的。我不認爲OnException被稱爲兩次,因爲它是一個自定義屬性 - 我相信這也發生在標準的HandleError屬性,它現在簡單地可見,因爲我正在創建它的記錄。最終,我想記錄所有未處理的異常(一次),同時保留[HandleError]提供的功能,特別是爲特定的方法異常設置不同的視圖。有沒有一種乾淨的方式來做到這一點?

回答

9

我相信我找到了一個簡潔的解決了這個自己。擴展HandleError似乎是一個好主意,但現在我認爲這是朝錯誤方向邁出的一步。我不想以任何不同的方式處理任何錯誤,只需在HandleError拾取它們之前寫入例外即可記錄一次。正因爲如此,默認的HandleError可以保持原樣。雖然可以多次調用OnException,但在HandleErrorAttribute的標準實現中似乎完全是良性的。

相反,我創建了一個異常記錄過濾器:

public class LoggedExceptionFilter : IExceptionFilter 
    { 
     public void OnException(ExceptionContext filterContext) 
     { 
      // logging code 
     } 
    } 

它不需要從FilterAttribute太繼承,因爲它只是RegisterGlobalFilters一起HandleErrorAttribute內註冊一次。

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new LoggedExceptionFilter()); 
     filters.Add(new HandleErrorAttribute()); 
    } 

這樣就可以在不改變標準[HandleError]功能

+1

謝謝!這對我也很有用。 – abjbhat 2013-08-01 06:40:53

+0

嗨,很好的解決方案,但你怎麼能從異常的來源,如類/方法的名稱獲得更多的信息? – Patrick 2014-04-17 11:01:38

2

你可以創建一個自定義IFilterProvider將檢查過濾器已經被應用到行動:而不是與GlobalFilterCollection註冊您的過濾器

public class MyFilterProvider : IFilterProvider 
{ 
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     if (!actionDescriptor.GetFilterAttributes(true).Any(a => a.GetType() == typeof(MyHandleErrorAttribute))) 
     { 
      yield return new Filter(new MyHandleErrorAttribute(), FilterScope.Global, null); 
     } 
    } 
} 

然後,你會登記在Application_Start()您的過濾器供應商

FilterProviders.Providers.Add(new MyFilterProvider()); 

或者(類似於@馬克提出的),你可以明確地設置的ExceptionContext

public class MyHandleErrorAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext context) 
    { 
     if(context.ExceptionHandled) return; 

     // Write to log code 
     base.OnException(context); 
     context.ExceptionHandled = true; 
    } 
} 
3

0財產試試這個,

public class MyHandleErrorAttribute : HandleErrorAttribute 
{ 
    public override void OnException(ExceptionContext context) 
    { 
     var exceptionHandled = context.ExceptionHandled; 

     base.OnException(context);       

     if(!exceptionHandled && context.ExceptionHandled) 
      // log the error. 
    } 
} 
+0

這是一個完美的技巧。謝謝你對我很好。謝謝 – mayk 2016-05-13 11:11:21

-1

我居然找到了解決方案,從發射兩次保持onException的方法整齊地記錄異常。如果您使用在FilterConfig.RegisterGlobalFilters()方法,註釋掉的HandleErrorAttribute的登記:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     //filters.Add(new HandleErrorAttribute()); 
    } 
} 

事實上,我還使用了內置HandleErrorAttribute不註冊它,它工作得很好。我只需要打開自定義錯誤:

<system.web> 
    <customErrors mode="On" /> 
</system.web> 
+0

也許你應該重新閱讀這個問題。他想同時使用兩者。 – 2013-05-23 23:54:22