来自 IOperationInvoker 的方法名称

本文关键字:方法 IOperationInvoker 来自 | 更新日期: 2023-09-27 18:33:23

我最近读了Juval Lowy的《Programming WCF Services, Third Edition》。我正在利用下面显示的他ParameterTracerInvoker : GenericInvoker使用 NLOG 跟踪日志。它工作得很好,除了我认为可能不可能的一件事,那就是获取被调用MethodName。正如您在PreInvoke方法中看到的那样,我正在记录输入,而不是方法名称。有人知道如何检索方法名称吗?

public abstract class GenericInvoker : IOperationInvoker
{
    internal readonly IOperationInvoker _oldInvoker;
    public GenericInvoker(IOperationInvoker oldInvoker)
    {
        Debug.Assert(oldInvoker != null);
        _oldInvoker = oldInvoker;
    }
    public virtual object[] AllocateInputs()
    {
        return _oldInvoker.AllocateInputs();
    }
    /// <summary>
    /// Exceptions here will abort the call
    /// </summary>
    /// <returns></returns>
    protected virtual void PreInvoke(object instance, object[] inputs)
    { }
    /// <summary>
    /// Always called, even if operation had an exception
    /// </summary>
    /// <returns></returns>
    protected virtual void PostInvoke(object instance, object returnedValue, object[] outputs, Exception exception)
    { }
    public object Invoke(object instance, object[] inputs, out object[] outputs)
    {
        PreInvoke(instance, inputs);
        object returnedValue = null;
        object[] outputParams = new object[] { };
        Exception exception = null;
        try
        {
            returnedValue = _oldInvoker.Invoke(instance, inputs, out outputParams);
            outputs = outputParams;
            return returnedValue;
        }
        catch (Exception operationException)
        {
            exception = operationException;
            throw;
        }
        finally
        {
            PostInvoke(instance, returnedValue, outputParams, exception);
        }
    }
    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
    {
        PreInvoke(instance, inputs);
        return _oldInvoker.InvokeBegin(instance, inputs, callback, state);
    }
    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
    {
        object returnedValue = null;
        object[] outputParams = { };
        Exception exception = null;
        try
        {
            returnedValue = _oldInvoker.InvokeEnd(instance, out outputs, result);
            outputs = outputParams;
            return returnedValue;
        }
        catch (Exception operationException)
        {
            exception = operationException;
            throw;
        }
        finally
        {
            PostInvoke(instance, returnedValue, outputParams, exception);
        }
    }
    public bool IsSynchronous
    {
        get
        {
            return _oldInvoker.IsSynchronous;
        }
    }
}
public class ParameterTracerInvoker : GenericInvoker
{
    private readonly Logger _logger = LogManager.GetCurrentClassLogger();
    public ParameterTracerInvoker(IOperationInvoker oldInvoker)
        : base(oldInvoker)
    {
    }
    protected override void PreInvoke(object instance, object[] inputs)
    {
        //_logger.Trace(((SyncMethodInvoker)_oldInvoker).MethodName);
        _logger.Trace("Input Parameters:");
        foreach (object argument in inputs)
        {
            if (argument != null)
            {
                _logger.Trace(argument.ToString());
            }
            else
            {
                _logger.Trace("null");
            }
        }
    }
    protected override void PostInvoke(object instance, object returnedValue, object[] outputs, Exception exception)
    {
        foreach (object output in outputs)
        {
            _logger.Trace("Output Parameters:");
            _logger.Trace(output.ToString());
        }
        returnedValue = "aaaaaaaaaaaa";
        _logger.Trace("Returned: " + returnedValue ?? String.Empty);
    }
}

来自 IOperationInvoker 的方法名称

IOperationInvoker本身不会给你操作名称,但为了使用自定义调用程序,你通常会使用操作行为。该行为有权访问操作名称,并且可以将其传递给自定义调用程序:

public class ParameterTracerOperationBehavior : IOperationBehavior
{
    // ...
    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        var originalInvoker = dispatchOperation.Invoker;
        var operationName = operationDescription.Name;
        var newInvoker = new ParameterTracerInvoker(originalInvoker, operationName);
        dispatchOperation.Invoker = newInvoker;
    }
}
public class ParameterTracerInvoker
{
    private readonly Logger _logger = LogManager.GetCurrentClassLogger();
    private readonly string operationName;
    public ParameterTracerInvoker(IOperationInvoker oldInvoker, string operationName)
        : base(oldInvoker)
    {
        this.operationName = operationName;
    }
    // ...
}

我的完整示例

public class WcfTracingOperationBehavior : IOperationBehavior
  {
    #region Implementation of IOperationBehavior
    public void Validate(OperationDescription operationDescription)
    {
    }
    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Invoker = new WcfTracingOperationInvoker(dispatchOperation.Invoker, operationDescription);
    }
    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }
    #endregion
  }

public class WcfTracingOperationInvoker : IOperationInvoker
      {
        private readonly IOperationInvoker _originalInvoker;
        private string ServiceFullName { get; set; }
        private string ServiceName { get; set; }
        private string MethodName { get; set; }
        public WcfTracingOperationInvoker(IOperationInvoker originalInvoker, OperationDescription operationDescription)
        {
            _originalInvoker = originalInvoker;
            var declaringType = operationDescription.SyncMethod.DeclaringType;
            if (declaringType != null)
            {
                ServiceFullName = declaringType.FullName;
                ServiceName = declaringType.Name;
            }
            MethodName = operationDescription.SyncMethod.Name;
        }
        #region Implementation of IOperationInvoker
        public object[] AllocateInputs()
        {
            SetMethodInfo();
            return _originalInvoker.AllocateInputs();
        }
        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            var result = _originalInvoker.Invoke(instance, inputs, out outputs);
            return result;
        }
        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            return _originalInvoker.InvokeBegin(instance, inputs, callback, state);
        }
        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return _originalInvoker.InvokeEnd(instance, out outputs, result);
        }
        public bool IsSynchronous
        {
            get { return _originalInvoker.IsSynchronous; }
        }
        #endregion

        private void SetMethodInfo()
        {
            // The WcfContext is some my stuff.
            var wcfTraceActivity = WcfContext<WcfTraceActivity>.Current;
            wcfTraceActivity.ServiceName = ServiceName;
            wcfTraceActivity.ServiceFullName = ServiceFullName;
            wcfTraceActivity.MethodName = MethodName;
        }
      }