Skip Navigation LinksHome > View Post

Propagating the ActivityId to a WCF service

In case you don't already know, the ActivityId is something we use to correlate trace events when logging so we know which 'start' goes with which 'stop' on a busy server. I wrote about it in this post.

Immediately after that post I blogged about a custom WCF message inspector that smuggled the ActivityId in a header. It turns out this was (almost*) superfluous as the WCF had recognised this as a common thing to want to do and added it as a feature.

However, it's pretty tricky to get this working as one of our readers discovered. On first impressions it's just a case of adding the System.ServiceModel trace source and set propagateActivity to true.

<system.diagnostics>
    <sources>
        <source name="System.ServiceModel" propagateActivity="true"/>
    </sources>
</system.diagnostics>

"The propagateActivity attribute indicates whether the activity should be propagated to other endpoints that participate in the message exchange."

Easy right? No. This wouldn't do anything. Nada.

Why? Not sure what the reason is but you must have a listener configured (even if you're doing nothing with it). I usually call it ignored to make it obvious.

<system.diagnostics>
    <sources>
        <source name="System.ServiceModel" propagateActivity="true">
            <listeners>
                <add name="ignored" type="System.Diagnostics.DefaultTraceListener" />
            </listeners>
        </source>
    </sources>
</system.diagnostics>

Bingo! Now our ActivityId will propagate from the client to the server. Nice. But remember... You must configure this at both the client AND the server for it to work!

Anything else? Oh yes...

The next thing that's likely to go wrong is that you might actually want to look at some of the output from the System.ServiceModel trace source so you turn up the volume and set the switchValue to 'All', for example, and add a real listener:

<source name="System.ServiceModel" switchValue="All" propagateActivity="true">
    <listeners>
        <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "c:\log\Traces.svclog" />
    </listeners>
</source>

All of a sudden the propagateActivity behaviour seems to break. Sure, you have an activityId at the server but it's different to the one you set at the client. Hmmm.

The documentation states why:

"If propagateActivity=true and ActivityTracing=off for a ServiceModel trace listener (regardless of whether tracing is enabled on ServiceModel), the following happen on either the client or server:
   - On operation request or sending response, the activity ID in TLS is propagated out of user code until a message is formed. An activity ID header is also inserted into the message before it is sent.
   - On receiving request or receiving response, the activity ID is retrieved from the message header as soon as the received message object is created. The activity ID in TLS is propagated as soon as the message disappears from scope until user code is reached."

So, if the switchValue is set to a value that includes ActivityTracing then the behaviour changes and you lose your ActivityId on server side. I hate this. It means if I want to use ActivityTracing (or All) in the System.ServiceModel trace source then we can't use propagateActivity in the way we'd expect.

( * which is why the message inspector I mentioned earlier is only almost superfluous and not totally.)

And remember, once again, ActivityTracing must be off at both the client and the server for propagateActivity to actually propagate your ActivityId.

Tags: ASP.NET

 
Josh Post By Josh Twist
2:07 AM
29 May 2008

» Next Post: Speaking at NxtGenUG's FEST '08
« Previous Post: Lambda and Expression Trees

Comments are closed for this post.

Posted by Benjay @ 16 Nov 2010 6:49 PM
Hello, maybe it's too late for a question on this topic, but as I didn't found any answer on google...

I managed to propagate the activity id as you described in your sample, but my probem is that the CorrelationManager.ActivityId is not set in my IOperationInvoker. Inside the service all is ok, but just before the call in my custom IOperationInvoker the guid is empty... Do you have any ideas on this ?

Thanks !

Posted by Benjay @ 17 Nov 2010 8:47 AM
Ok understood, thanks to reflector my second best friends after google :)

The activityId is set by the IOperationInvoker provided by the framework, in my case the SyncMethodInvoker. So it's totally normal that before the call to the innerInvoker the activityId is null. Using reflector you can get the code to reproduce this behavior :

Guid activityId = ActivityIdHeader.ExtractActivityId(OperationContext.Current.IncomingMessage);

But, once again, you have to manage with some internal class or method, that you have to duplicate in your code...

Posted by Josh @ 19 Nov 2010 5:10 PM
Thanks for coming back with your solution!

Posted by ngochoa-hue @ 25 Apr 2011 10:33 AM
LAM ON GIUP TOI LOI NAY ! CAM ON

© 2005 - 2014 Josh Twist - All Rights Reserved.