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 回答