Подтвердить что ты не робот

Атрибут службы WCF для вызовов и исключений журнала вызовов

У меня есть требование для регистрации каждого вызова метода в службе WCF и любых исключений. Это привело к большому избыточному коду, потому что каждый метод должен включать в себя шаблон, подобный этому:

[OperationContract]
public ResultBase<int> Add(int x, int y)
{
    var parameters = new object[] { x, y }
    MyInfrastructure.LogStart("Add", parameters);
    try
    {
        // actual method body goes here
    }
    catch (Exception ex)
    {
        MyInfrastructure.LogError("Add", parameters, ex);
        return new ResultBase<int>("Oops, the request failed", ex);
    }
    MyInfrastructure.LogEnd("Add", parameters);
}

Есть ли способ инкапсулировать всю эту логику в атрибут MyServiceLoggingBehaviorAttribute, который я мог бы применить к классу (или методам) службы следующим образом:

[ServiceContract]
[MyServiceLoggingBehavior]
public class MyService
{
}

Примечание # 1

Я понимаю, что это можно сделать с помощью Aspect-ориентированного программирования, но на С# единственный способ сделать это - изменить байт-код, который требует использования сторонний продукт, такой как PostSharp. Я хотел бы избежать использования коммерческих библиотек.

Примечание # 2

Обратите внимание, что приложения Silverlight являются основными потребителями этой услуги.

Примечание № 3

Протокол трассировки WCF является хорошим вариантом в некоторых случаях, но он не работает здесь, поскольку, как отмечалось выше, мне нужно проверить, а в случае изменения исключения, возвращаемого значения.

4b9b3361

Ответ 1

Да, можно инкапсулировать этот вид ведения журнала, используя точки расширяемости, встроенные в WCF. На самом деле существует несколько возможных подходов. Тот, который я описываю здесь, добавляет IServiceBehavior, который использует пользовательский IOperationInvoker и не требует каких-либо изменений в web.config.

Здесь есть три части.

  • Создайте реализацию IOperationInvoker, которая обертывает вызов метода в необходимых журналах и обработке ошибок.
  • Создайте реализацию IOperationBehavior, которая применяет invoker с шага 1.
  • Создайте IServiceBehavior, который наследует от Attribute и применяет поведение с шага 2.

Шаг 1 - IOperationInvoker

Суть IOperationInvoker - это метод Invoke. Мой класс обертывает базового invoker в блок try-catch:

public class LoggingOperationInvoker : IOperationInvoker
{
    IOperationInvoker _baseInvoker;
    string _operationName;

    public LoggingOperationInvoker(IOperationInvoker baseInvoker, DispatchOperation operation)
    {
        _baseInvoker = baseInvoker;
        _operationName = operation.Name;
    }

    // (TODO stub implementations)

    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        MyInfrastructure.LogStart(_operationName, inputs);
        try
        {
            return _baseInvoker.Invoke(instance, inputs, out outputs);
        }
        catch (Exception ex)
        {
            MyInfrastructure.LogError(_operationName, inputs, ex);
            return null;
        }
        MyInfrastructure.LogEnd("Add", parameters);
    }
}

Шаг 2 - IOperationBehavior

Реализация IOperationBehavior просто применяет настраиваемый диспетчер к операции.

public class LoggingOperationBehavior : IOperationBehavior
{
    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Invoker = new LoggingOperationInvoker(dispatchOperation.Invoker, dispatchOperation);
    }

    // (TODO stub implementations)
}

Шаг 3 - IServiceBehavior

Эта реализация IServiceBehavior применяет поведение операции к службе; он должен наследовать от Attribute, чтобы он мог применяться как атрибут класса сервиса WCF. Реализация для этого является стандартной.

public class ServiceLoggingBehavior : Attribute, IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            foreach (OperationDescription operation in endpoint.Contract.Operations)
            {
                IOperationBehavior behavior = new LoggingOperationBehavior();
                operation.Behaviors.Add(behavior);
            }
        }
    }
}

Ответ 2

Вы можете попробовать Audit.NET с помощью Audit.WCF. Он может регистрировать взаимодействие службы WCF и совместим с асинхронными вызовами.

Все, что вам нужно сделать, - это украсить ваш класс или методы WCF атрибутом AuditBehavior:

[AuditBehavior()]
public class OrderService : IOrderService
{ ... }

Расширение WCF использует IOperationInvoker реализацию Invoke и InvokeBegin/InvokeEnd. Вы можете проверить код здесь.