2015-08-17 39 views
0

我想集中管理某種方法的異常處理,但我似乎無法達到那裏。與Autofac和DynamicProxy2異常處理AOP

public class ExceptionInterceptor : IInterceptor 
{ 
    private readonly Logger _logger; 

    public ExceptionInterceptor(Logger logger) 
    { 
     _logger = logger; 
     Measure.Configure(new StatsdConfig()); 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     try 
     { 
      invocation.Proceed(); 
      //if ((Task<System.Threading.Tasks.VoidTaskReturn>) invocation.ReturnValue.Status == "Failed") 
      //{ 
      // throw new Exception(invocation.ReturnValue.Exception[0]); 
      //} 
     } 
     catch (Exception e) 
     { 
      var errorMessage = 
       String.Format(
        "An error occurred while retrieving fund data. Error Message: {0} Inner Exception: {1}", 
        e.Message, e.InnerException != null ? e.InnerException.Message : "<None>"); 

      _logger.Log(errorMessage); 
      Measure.Counter("Exception", 1); 
      Measure.Event("Exception", errorMessage); 
      throw; 
     } 

    } 

我一個模塊中佈線此像這樣:

builder.RegisterType<DataConsumer>(). 
      As<IConsumer<DataRequest>>(). 
      EnableInterfaceInterceptors(). 
      InterceptedBy(typeof(ExceptionInterceptor)); 

builder.RegisterType<ExceptionInterceptor>().AsSelf(); 
var loggingInterceptor = new LoggingInterceptor(Logger); 
builder.Register(c => loggingInterceptor); 

然而,當我拋出異常方法調用作爲例外拋出此不能上升到攔截器,所以它永遠不會進入catch塊。 有什麼方法可以在攔截器中捕獲截獲的方法的異常?

由於某些原因,我也無法訪問invocation.ReturnValue.Status,因此無法測試是否存在拋出的異常以便重新拋出。

任何人都可以闡明我可能做什麼也沒有在這裏做什麼?

+0

您可以顯示'IConsumer '界面嗎?另外,你可以顯示在容器中註冊'ExceptionInterceptor'和'Logger'的代碼嗎? –

+0

@TravisIllig IConsumer 接口是這一個http://www.nudoq.org/#!/Packages/MassTransit/MassTransit/IConsumer,它只是IoC容器的標記接口。 – cmdel

+0

@TravisIllig我也編輯了問題 – cmdel

回答

-1

它似乎是不可能的目標代理拋出的異常被推到攔截,因此我試圖做沒有工作。我最終處理了他們發生的課程中的例外情況。

失望我沒有設法讓我的工作方式,我打算。

+2

攔截器無法處理異常並非完全正確。我有一份工作報告,我會很快發佈。問題將以它的方式進行,這就是爲什麼我要求更多細節。 –

2

由於信息不完整,我很難再現您的問題。例如,您注意到IConsumer<T>接口是MassTransit接口,但the interface in MassTransit isn't generic。它還特別提到該接口應該是僅用於IoC容器的標記,這可能會對你的接線有一些影響。

首先,讓我們發佈一個工作異常處理示例。是自包含的,我會代替IConsumer<T>和一個簡單的實現創建IWorker<T>接口:

public interface IWorker<T> 
{ 
    bool DoWork(T message); 
} 

public class StringWorker : IWorker<string> 
{ 
    public bool DoWork(string message) 
    { 
     throw new DivideByZeroException(); 
    } 
} 

現在,我將創建一個簡單的異常記錄,只是管信息到控制檯。

public class ExceptionLogger : IInterceptor 
{ 
    private readonly TextWriter _output; 

    public ExceptionLogger(TextWriter output) 
    { 
     _output = output; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     try 
     { 
      invocation.Proceed(); 
     } 
     catch(Exception ex) 
     { 
      _output.WriteLine("Logged Exception: {0}", ex.Message); 
      throw; 
     } 
    } 
} 

然後我可以線它,看到它在這樣的動作:

var builder = new ContainerBuilder(); 
builder.RegisterInstance(Console.Out).As<TextWriter>(); 
builder.RegisterType<ExceptionLogger>(); 
builder.RegisterType<StringWorker>() 
     .As<IWorker<string>>() 
     .EnableInterfaceInterceptors() 
     .InterceptedBy(typeof(ExceptionLogger)); 

var container = builder.Build(); 
var worker = container.Resolve<IWorker<string>>(); 
worker.DoWork("Test!"); 

當我運行它,我的程序死掉之前控制檯(與未處理的異常上看到 - 記我的處理程序沒有嚥下去,只是記錄吧):

Logged Exception: Attempted to divide by zero. 

所以它的工作。

我認爲您的環境中有更多可能會造成麻煩的地方。這可能是你認爲不相關的東西,但實際上很重要。

一般的事情進行調查:

  • 暫時更新DataConsumer立即拋出一個異常,內部的接口方法之一。在構建容器之後,解析一個IConsumer<DataRequest>並調用該接口方法。它會記錄嗎?
  • 看看你期待會發生日誌記錄的地方。您是否正在解決並與IConsumer<DataRequest>或其他工作?它封裝了接口方法,而不是對象類型,因此並非涵蓋所有方法。
  • 在攔截器中設置斷點並查看是否有任何調用正在通過它。如果沒有被擊中,它將不會捕獲異常。 :)
  • 檢查是否有其他異常處理策略或代碼正在執行。例如,一些人使用企業庫異常處理塊來處理異常,這可能會干擾您在此處的工作。
  • 我沒有使用MassTransit,但檢查是否有任何其他對象代理正在進行。 (令人懷疑,但我知道我已經遇到過Glimpse這樣的產品,所以最終會出現代理纏繞在代理上,這會變得具有挑戰性。)
  • 實際上是否在您認爲的地方發生異常?它可能正在發生,並且正在處理某處未包含代理的地方。

基本上,減少工件到可能的最小集合,直到你可以看到它工作,然後慢慢擴大,直到你找到它分解的地方。我不知道這些是否適用於您的情況,但如果我正在排除故障,這些是我開始考慮的事情。

但是... 使用攔截器的AOP時尚異常處理確實有效,所以這是另一回事導致的挑戰。

+0

它也適用於我,謝謝分享一個工作示例。 –