Ответ 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);
}
}
}
}