2011-01-24 56 views
1

我想實現在將使用log4net的記錄異常WCF,IErrorHandler和log4net的

[AttributeUsage(AttributeTargets.Class)] 
public class AErrorHandlerBehaviorAttribute : Attribute, IServiceBehavior, IErrorHandler{ 

    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    protected Type ServiceType { get; set; } 
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
    //Dont do anything 
    } 

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection <ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 
    { 
    //dont do anything 
    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
    ServiceType = serviceDescription.ServiceType; 
    foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) 
    { 
    dispatcher.ErrorHandlers.Add(this); 
    } 
    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
    fault = null; //Suppress any faults in contract 
    } 

    public bool HandleError(Exception error) 
    { 
    log.Error("Page Load failed : " + error.Message); 
    return false; 
    } 
} 

然後我實現使用行爲的服務的WCF服務的錯誤處理行爲。如果我在服務內聲明的ILog變量

[AErrorHandlerBehavior] 
public class AService : IAService 
{ 

    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

     ....//various methods 
} 

但是這工作得很好,當ILog的變量未聲明的日誌記錄停止工作。

[AErrorHandlerBehavior] 
public class AService : IAService 
{ 

    //private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

     ....//various methods 
} 

理想的情況下,我不希望有聲明的ILog變量在我每次產生的服務,特別是當它在行爲已聲明。

有人可以請解釋一)爲什麼這必須在行爲和服務中聲明。和b)避免雙重聲明的任何方法或c)更好的登錄wcf的方法。

回答

2

我不相信你使用,以解決Log對象的代碼:

private static readonly ILog log = 
    LogManager.GetLogger(
    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType 
); 

這將始終解析到其內的代碼行寫入類型,因爲它首先解析汽車 - 定義的靜態構造函數(與周圍類的MethodInfo.GetCurrentMethod())然後獲取它的聲明類型。

好吧,我說總是 ...

我不喜歡這種模式,因爲它含蓄地依賴於你沒有物理寫入自己(因此代碼編譯器的內部特徵即可能隨時改變);如果你明確地將它放在你自己編寫的靜態構造函數中,它會稍微好一些。

如果你想這樣做,然後用

typeof(_whatever_type_you_declare_it_in_); 

...不依賴於編譯器和運行時間。

同樣 - 我有一種感覺,你可能會在錯誤的信念下使用這種模式,它會解析到定義屬性的服務,但它不會。

您是否打算通過行爲級別的默認值來控制要在服務級別使用的日誌?

如果是這樣,那麼我建議你:

1)實例級ILog屬性添加到您的行爲,稱爲_serviceLog

2)在你的實現ApplyDispatchBehaviour做到這一點:

_serviceLog = LogManager.GetLogger(serviceDescription.ServiceType); 

3)然後你的執行HandleError可能如下:

public bool HandleError(Exception error) 
{ 
    //use the service-level log, or a default 
    ILog targetLog = _serviceLog ?? log; 
    if(targetLog != null) 
    targetLog.Error("Page Load failed : " + error.Message); 
    return false; 
} 
+0

Andras,感謝您的回覆。我很努力地看到如何獲得服務描述。指示如何獲得此信息的任何機會。我真正想要做的是得到錯誤拋出的最初位置。我有一種感覺,這可能有點困難,因爲看着日誌記錄錯誤是在行爲中拋出。這當然是有道理的,但不是我想要的 – KiwiInLondon 2011-01-25 08:33:48

0

實際的問題,忽略什麼是正確的方式來獲取記錄器,是在我沒有配置記錄器的行爲。

此修復程序是簡單的配置語句添加到ApplyDispatchBehavior

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
     { 
      XmlConfigurator.Configure();    
      foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) 
      { 
       dispatcher.ErrorHandlers.Add(this); 
      } 
     } 

我相信我爲什麼會記錄從行爲體沒有,這是因爲在服務中聲明的ILog引起記錄器的構成的理由在錯誤發生之前