Managing OperationContext in WF 4 using the
ISendMessageCallback & IReceiveMessageCallback
WF 4 raised the level of abstraction for writing workflow
services and their clients by defining Send & Receive
messaging activities. These activities hides lot of WCF plumbing from you and
as result, some useful components like OperationContext
are also not available in the usual WCF way. For example,
Ø When
using Send activity, you never see the ChannelFactory/Channel so you can’t
scope an OperationContext around them.
Ø When
using Receive activity, activities following the Receive might execute
on a different thread (than the WCF dispatcher thread) in which case you again
wouldn’t get OperationContext.
If you done any WCF programming, you would agree that
OperationContext can be very useful on both Send/Receive side:
Ø On
the send side, you can use OperationContext for sending additional message
headers as part of the outgoing message or you can use OperationContext to add
additional message properties to the outgoing message.
Ø On
the receive side, you can use OperationContext to retrieve very useful
information including but not limited to security information related to the
incoming message.
So in short, access to OperationContext on Send/Receive side
can be very useful and luckily WF 4 has enabled this using a callback mechanism
based on IReceiveMessageCallback
& ISendMessageCallback.
IReceiveMessageCallback(s) are invoked just after the
message is received by a Receive activity. Similarly, ISendMessageCallback(s)
are invoked just before the message is sent on wire.
To attach these callback(s) to Send & Receive
activities, they must be available as execution properties when Send/Receive
executes. Execution properties are WF mechanism to enable Thread Local Storage
(TLS) in a thread agnostic way. A common method of adding execution properties
to and activity is to create a parent scope activity and set the execution properties
as part of parent execution. Here is an example.
public class OperationContextScope : NativeActivity
{
public
Activity Body { get;
set; }
protected
override void
CacheMetadata(NativeActivityMetadata
metadata)
{
metadata.AddChild(this.Body);
}
protected
override void
Execute(NativeActivityContext context)
{
context.Properties.Add("MessageInspector", new SendMessageInspector());
context.ScheduleActivity(this.Body);
}
[DataContract]
class SendMessageInspector : ISendMessageCallback
{
public void
OnSendMessage(OperationContext
operationContext)
{
var h1 = MessageHeader.CreateHeader("yourName", "urn:personal",
"zuahmed");
operationContext.OutgoingMessageHeaders.Add(h1);
}
}
}
Once you defined a scope activity like above you can just
wrap your actual Send/Receive inside this scope to activate your inspector.
WorkflowInvoker.Invoke(
new OperationContextScope
{
Body =
new Send {
OperationName = "Ping",
ServiceContractName = "IPingService",
EndpointConfigurationName = "PingEpr"
}
}
);
IReceiveMessageCallback and Receive activity is exactly the
same and I leaving that as an exercise for the readers J
In this post, I have shown you a general purpose mechanism
to interact with an OperationContext while using WF 4 messaging activities. In
next few posts, I’ll use this mechanism to add some very useful security
features to WF 4. Stay tuned...