tags:

views:

196

answers:

3

Hi,

I would like to compute time that spans between two particular moments:

- start moment would be call to method IDispatchMessageInspector
.AfterReceiveRequest
- end moment would be call to method IDispatchMessageInspector.BeforeSendReply

In fact, I would like to compute time that is needed to execute service call user code. I thought that those two methods of IDispatchMessageInspector are good place to hook. But unfortunately I don't know how to associate AfterReceiveRequest for message with corresponding BeforeSendReply call.

Thanks Pawel.

+1  A: 

Here's a parameter inspector I once wrote to measure performance of my WCF service methods. Notice that a Stopwatch is started and returned in the BeforeCall method which allows you to retrieve it in the AfterCall method as the correlationState parameter:

public class PerformanceCountersInspector : IParameterInspector
{
    public object BeforeCall(string operationName, object[] inputs)
    {
        return Stopwatch.StartNew();
    }

    public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
    {
        var watch = (Stopwatch)correlationState;
        watch.Stop();
        var time = watch.ElapsedMilliseconds;
        // Do something with the result
    }
}

The difference here is that using a parameter inspector will not take into account the time taken to serialize input/output parameters. It will only account for the operation time. If you want to include serialization time you might use IDispatchMessageInspector. The BeforeSendReply method also has a correlationState that works the same.


UPDATE:

You could configure the parameter inspector in web.config by writing a behavior extension:

public class PerformanceCountersBehaviorExtension : BehaviorExtensionElement, IServiceBehavior
{
    public override Type BehaviorType
    {
        get { return typeof(PerformanceCountersBehaviorExtension); }
    }

    protected override object CreateBehavior()
    {
        return this;
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
        {
            foreach (var endpoint in channelDispatcher.Endpoints)
            {
                foreach (var operation in endpoint.DispatchRuntime.Operations)
                {
                    var inspector = new PerformanceCountersInspector();
                    operation.ParameterInspectors.Add(inspector);
                }
            }
        }
    }

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

And in your configuration file you register the extension:

<services>
  <service name="MyAssembly.MyService" behaviorConfiguration="returnFaults">
    <endpoint address="" binding="basicHttpBinding" contract="MyAssembly.IMyServiceContract"/>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="returnFaults">
      <serviceDebug includeExceptionDetailInFaults="true"/>
      <serviceMetadata httpGetEnabled="true"/>
      <perfCounters />
    </behavior>
  </serviceBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="perfCounters" type="MyAssembly.PerformanceCountersBehaviorExtension, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
Darin Dimitrov
Outstanding :) Thanks Darin
dragonfly
A: 

What about this?

public object AfterReceiveRequest(
    ref System.ServiceModel.Channels.Message request, 
    IClientChannel channel, InstanceContext instanceContext)
{
    return DateTime.Now;
}

public void BeforeSendReply(
    ref System.ServiceModel.Channels.Message reply, object correlationState)
{
    TimeSpan elapsed = DateTime.Now - ((DateTime)correlationState);
}
Rubens Farias
A: 

Bingo ! Thanks ! It is possible to attach that mechanizm to application from app.config file?

dragonfly
I've updated my post to show an example of how you could register the parameter inspector in your configuration file. And please use the comments section for this kind of questions.
Darin Dimitrov