1

log4netを使用して例外をログに記録するwcfサービスにエラー処理動作を実装しようとしています

[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;
  }
}

次に、この動作を使用するサービスを実装します。サービス内で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変数を宣言する必要はありません。

誰かがa)これが振る舞いとサービスの両方で宣言されなければならない理由を説明してもらえますか?b)二重宣言を回避する方法またはc)wcfにログインするためのより良い方法。

4

2 に答える 2

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;
}
于 2011-01-24T21:15:23.160 に答える
0

ロガーを取得する正しい方法を無視した実際の問題は、ロガーを構成していない動作でした。

修正は、Configure ステートメントを追加するだけでした。ApplyDispatchBehavior

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

これなしで振る舞いからログに記録できた理由は、エラーがスローされる前に、サービスで ILog の宣言がロガーの構成を引き起こしたためだと推測します

于 2011-01-25T09:59:13.013 に答える