Method Name from IOperationInvoker

I recently read the WCF Services Program, the third edition of Juval Lowy. I use it ParameterTracerInvoker : GenericInvokershown below to track the log using NLOG. It works great, except that, it seems to me, it’s not possible what causes the call MethodName. As you can see in the method PreInvoke, I register the input, but not the name of the method. Does anyone know how to get the method name?

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);
    }
}
+3
source share
2 answers

Itself IOperationInvokerwill not give you the name of the operation, but to use the custom invoker, you usually use the operation behavior. The behavior has access to the name of the operation and can be passed to your custom call:

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

    // ...
}
+4
source

My complete example

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

  }

and

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

      }
+2
source

All Articles