3

我最近阅读了 Juval Lowy 的Programming WCF Services,第三版。我正在利用他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);
    }
}
4

2 回答 2

4

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;
    }

    // ...
}
于 2012-05-07T22:12:02.830 回答
2

我的完整示例

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;
        }

      }
于 2012-10-03T07:46:16.113 回答