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...