2011-01-24 3 views
1

Я пытаюсь реализовать поведение обработки ошибок на службе WCF, которая будет использовать 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; 
    } 
} 

Я тогда реализовать услугу, которая использует поведение. Это отлично работает, если я объявить переменную Илог в рамках услуги

[AErrorHandlerBehavior] 
public class AService : IAService 
{ 

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

     ....//various methods 
} 

Однако, когда переменная Илог не объявлена ​​лесозаготовительной перестает работать.

[AErrorHandlerBehavior] 
public class AService : IAService 
{ 

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

     ....//various methods 
} 

В идеале я не хочу, чтобы объявить переменную Илог в каждой службе я произвожу, особенно если он уже объявлен в поведении.

Не могли бы вы объяснить, пожалуйста, почему это должно быть объявлено как в поведении, так и в сервисе. и b) любой способ избежать двойного объявления или c) лучший способ регистрации в wcf.

ответ

2

Я не уверен в коде, который вы используете, чтобы решить, что Log объекта:

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

Это всегда будет разрешать к типу, в течение которого строка кода записывается как она решает сначала авто -defined static constructor (с MethodInfo.GetCurrentMethod() окружающего класса), а затем получает свой тип объявления.

Ну, я говорю всегда ...

мне не нравится этот вид шаблона, как это неявно полагается на код, который вы не физически письменного себя (и, следовательно, внутренняя особенность компилятора что can изменение в любое время); было бы немного лучше, если бы вы явно разместили его внутри статического конструктора, который вы пишете сами.

Если вы хотите сделать это, а затем использовать

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

+0

на самом деле я был немного толстым, должно быть, немного рано утром. Теперь я вижу параметр serviceDescription. Надо надевать очки. Спасибо за вашу помощь – KiwiInLondon

0

Фактическая проблема, игнорируя то, что является правильным способом получения регистратора, заключалось в том, что в поведении я не настроил регистратор.

Исправления было просто добавить оператор Configure к ApplyDispatchBehavior

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

Я предполагаю причину, почему я мог войти из behaiour без этого было потому, что декларация Илогов в службе вызвала конфигурацию регистратора перед тем как ошибка была сброшена

Смежные вопросы