Time for your operation execution using the Operation invoker.

Have you ever wanted to do something like this .

    // Define a service contract.

    [ServiceContract(Namespace="https://Microsoft.ServiceModel.Samples")]

    public interface ICalculator

    {

        [OperationContract]

        [PerfOperationBehavior]

        double Add(double n1, double n2);

        [OperationContract]

        double Subtract(double n1, double n2);

       

        [OperationContract]

        double Multiply(double n1, double n2);

       

        [OperationContract]

        double Divide(double n1, double n2);

    }

Where you probably wanted to write some code to log the time for the operation or just update some performance counter on the server. If you are already familiar with Operation invoker then the rest rest of the post is just a waste of time since i just wanted to show how the operation invoker could be used pretty much inject your code into the pipeline to see what is the execution time of your operation.

These are pretty much the steps you need to do.

  1. Create an operation behavior obviously since you want to attach to the operation.
  2. Implement the IOperationInvoker for kind of intercepting operation invocation.
  3. Attach a counter extension to log the start and end of the operation.  

And you pretty much have your behavior you can just add on the operation.

Here is the behavior and the classes required to implement this and shows a very bare bone implementation of the ticks that would occur between invocations of an operation.

FInd the full solution attached below.

using System;

using System.Collections.Generic;

using System.Text;

using System.ServiceModel.Description;

using System.ServiceModel.Dispatcher;

using System.ServiceModel;

using System.Diagnostics;

namespace Microsoft.Samples.Wcf.Performance

{

    [AttributeUsage(AttributeTargets.Method)]

    public class PerfOperationBehavior : System.Attribute, IOperationBehavior

    {

        #region IOperationBehavior Members

        void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription,

            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

        {

        }

        void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription,

            System.ServiceModel.Dispatcher.ClientOperation clientOperation)

        {

        }

        void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription,

            System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)

        {

            dispatchOperation.Invoker = new PerfCounterOperationInvoker(dispatchOperation.Invoker);

        }

        void IOperationBehavior.Validate(OperationDescription operationDescription)

        {

        }

        #endregion

    }

    internal class PerfCounterOperationInvoker : IOperationInvoker

    {

        IOperationInvoker innerOperationInvoker;

        public PerfCounterOperationInvoker(IOperationInvoker invoker)

        {

            this.innerOperationInvoker = invoker;

        }

        #region IOperationInvoker Members

        object[] IOperationInvoker.AllocateInputs()

        {

            return this.innerOperationInvoker.AllocateInputs();

        }

        object IOperationInvoker.Invoke(object instance, object[] inputs, out object[] outputs)

        {

            OperationContext.Current.Extensions.Add(new PerfOperationContextExtension());

            try

            {

                return this.innerOperationInvoker.Invoke(instance, inputs, out outputs);

            }

            finally

            {

                OperationContext.Current.Extensions.Remove(

                    OperationContext.Current.Extensions.Find<PerfOperationContextExtension>());

            }

        }

        IAsyncResult IOperationInvoker.InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)

        {

            OperationContext.Current.Extensions.Add(new PerfOperationContextExtension());

            return this.innerOperationInvoker.InvokeBegin(instance, inputs, callback, state);

        }

        object IOperationInvoker.InvokeEnd(object instance, out object[] outputs, IAsyncResult result)

        {

            OperationContext.Current.Extensions.Remove(

                OperationContext.Current.Extensions.Find<PerfOperationContextExtension>());

            return this.innerOperationInvoker.InvokeEnd(instance, out outputs, result);

        }

        bool IOperationInvoker.IsSynchronous

        {

            get { return this.innerOperationInvoker.IsSynchronous; }

        }

        #endregion

    }

    internal class PerfOperationContextExtension : IExtension<OperationContext>

    {

        long ticks;

       

        #region IExtension<OperationContext> Members

        public void Attach(OperationContext owner)

        {

            ticks = DateTime.Now.Ticks;

        }

        public void Detach(OperationContext owner)

        {

            ticks = DateTime.Now.Ticks - ticks;

            Debug.WriteLine(string.Format("Operation : {0} took {1} ticks",

                                    owner.IncomingMessageHeaders.Action,

                                    ticks));

        }

        #endregion

    }

}

 

 

 

 

OperationInvoker.zip