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
<source name="System.ServiceModel" propagateActivity="true"/>
"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.
<source name="System.ServiceModel" propagateActivity="true">
<add name="ignored" type="System.Diagnostics.DefaultTraceListener" />
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">
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "c:\log\Traces.svclog" />
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.
"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.
29 May 2008
» Next Post:
Speaking at NxtGenUG's FEST '08
« Previous Post:
Lambda and Expression Trees
Comments are closed for this post.
16 Nov 2010
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 ?
17 Nov 2010
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...
19 Nov 2010
Thanks for coming back with your solution!
25 Apr 2011
LAM ON GIUP TOI LOI NAY ! CAM ON