Search

Locations of visitors to this page

Categories

On this page

Authenticated messaging in WF 4
Managing OperationContext in WF 4
Durable Duplex Messaging in .Net 4 Beta2

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 49
This Year: 5
This Month: 0
This Week: 0
Comments: 69

Sign In

 Tuesday, January 19, 2010
Tuesday, January 19, 2010 4:44:20 PM (GMT Standard Time, UTC+00:00) ( WF 4 )

Authenticated messaging is one limitation in WF 4 as currently there is no API for setting up credentials to be used with a Send activity. Having said that, ChannelFactory used by Send activity still picks up the behaviour configuration from the config file.

So you can potentially write a custom behaviour to supply additional credentials to the Send activity. Let’s see a simple clientCredentialsAdapter behaviour which will enable you to setup userName/Password in config file. It’s almost always a bad idea to keep unencrypted password in config files so it is recommended that you should use config encryption to encrypt the behaviour section.

<behavior name="credentialAdapter">

  <clientCredentials>

    <serviceCertificate>

      <authentication certificateValidationMode="None"/>

      <defaultCertificate findValue="f7ad5a9dcc35f21ffc691925515f48eb44f5e07a" x509FindType="FindByThumbprint" storeLocation="CurrentUser" storeName="My"/>

    </serviceCertificate>

  </clientCredentials>

 

  <clientCredentialsAdapter>

    <userName userName="configUser" password="p@ssw0rd!"/>

  </clientCredentialsAdapter>

</behavior>

At this point, you can configure this behaviour on an endpoint used by a Send activity. This change will enable Send activity to use this userName/Password for securing outgoing messages.

public class ClientCredentialsAdapterBehavior : IEndpointBehavior

{

    ClientCredentialsAdapterBehaviorElement configElement;

 

    public ClientCredentialsAdapterBehavior(ClientCredentialsAdapterBehaviorElement configElement)

    {

        this.configElement = configElement;

    }

 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){}

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

    {

        var clientCredentials = endpoint.Behaviors.Find<ClientCredentials>();

        Adapt(clientCredentials);

    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }

 

    public void Validate(ServiceEndpoint endpoint){}

 

    void Adapt(ClientCredentials orignalCredentials)

    {

        orignalCredentials.UserName.UserName = configElement.UserName.UserName;

        orignalCredentials.UserName.Password = configElement.UserName.Password;

    }

}

So that was simpleJ What about a scenario where you have userName/Password as part of workflow state and you want to use that instead?

Well, in that case there is more work involved which I’ll discuss in next post.

Comments [0] | | # 
 Sunday, December 13, 2009
Sunday, December 13, 2009 12:26:43 PM (GMT Standard Time, UTC+00:00) ( WF 4 )

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

Comments [0] | | # 
 Wednesday, October 28, 2009
Wednesday, October 28, 2009 12:10:25 PM (GMT Standard Time, UTC+00:00) ( WF 4 )

Here I talked about couple of approaches to enable durable duplex messaging in .Net 3.5.

.NET 4 has added first class support for durable duplex messaging by extending Context Exchange Protocol to include a CallbackContext. So in addition to instanceId, a client application can send a callback context as part of the call.

Service, upon receiving the message, will start the long running work and when it needs to callback to client, it can simply use the address from the callback context.

From API perspective – a new property “ClientCallbackAddress” is added to ContextBindingElement. This property is also exposed on some higher level bindings like wsHttpContextBinding.

A new CallbackContextMessageProperty is also added to manipulate callback context from the application code.

  <bindings>

    <wsHttpContextBinding>

      <binding name="noSec" clientCallbackAddress="http://localhost:7080">

        <security mode="None"/>

      binding>

    wsHttpContextBinding>

  bindings>

Any messages sent using above binding will have a callback context attached to it. Please note callback context is only supported with SOAP based context exchange and that’s why clientCallbackAddress property is NOT exposed on basicHttpContextBinding as it uses HTTP cookies for context exchange.

var cf = new ChannelFactory<IRequestChannel>(new WSHttpContextBinding("noSec"),

                                             new EndpointAddress("http://localhost:8975/"));

var ccmp = new CallbackContextMessageProperty(new Dictionary<string,string>());

 

var msg = Message.CreateMessage(MessageVersion.Default, "urn:foo", "");

msg.Properties.Add(CallbackContextMessageProperty.Name, ccmp);

cf.CreateChannel().Request(msg);

This will produce following SOAP envelop and you can see CallbackContext header is added in outgoing message.

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">

  <s:Header>

    <a:Action s:mustUnderstand="1">urn:fooa:Action>

    <a:MessageID>urn:uuid:c7c03178-fa84-400e-8673-ad1ed28f0f79a:MessageID>

    <a:ReplyTo>

      <a:Address>http://www.w3.org/2005/08/addressing/anonymousa:Address>

    a:ReplyTo>

    <CallbackContext xmlns="http://schemas.microsoft.com/ws/2008/02/context">

      <CallbackEndpointReference>

        <a:Address>http://localhost:7080/a:Address>

        <a:ReferenceParameters>

          <Context xmlns="http://schemas.microsoft.com/ws/2006/05/context"/>

        a:ReferenceParameters>

      CallbackEndpointReference>

    CallbackContext>

    <a:To s:mustUnderstand="1">http://localhost:8975/a:To>

  s:Header>

  <s:Body>

    <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"/>

  s:Body>

s:Envelope>

On the server side, you can pick up the CallBackContext from the Message Properties and use it for call-backs. So far I have shown kind of a manual way of dealing with callback context. Workflow services in .Net 4 along with correlation feature has really simplified all this and you never need to muck with CallbackContextMessageProperty etc.

In your client workflow, simply make sure you have an active correlation handle on your send activity and then use a binding capable of transporting callback context (e.g. wsHttpContextBinding mentioned earlier)

 

In your server side workflow, simply make sure that Receive and Send (used for callback) activities are correlated either using implicitly or explicit correlation and that’s it.

You don’t need to specify Endpoint Address on your Send activity and it will automatically pick it from CallbackContext.

Comments [0] | | #