Implementing duplex messaging with BizTalk Services

It is undeniable that the use of BizTalk Services opens up a new set of possibilities for distributed applications. This post is not intended to provide an overview of BizTalk Services. My friend Clemens Vasters and the BizTalk Services team have been doing a fabulous job in that regard. Instead, I’ve decided to start blogging about different messaging scenarios that I have been implementing using BizTalk Services. Particularly, this post is focused on duplex messaging. As you might already know, duplex contracts are one of the features of WCF that allows implement scenarios on which both WCF endpoints exchange message independently.  Duplex messaging becomes difficult to adopt in scenarios on which the two endpoints reside on different organizations (different networks). This is partially given that a real world duplex messaging scenario requires a whole new set of considerations in terms of network resources (opening ports for receiving the callbacks), different security boundaries, etc. This is what makes BizTalk Services an ideal solution for this type of scenario. Now organizations don’t have to spend time and resources implementing the trusting mechanisms with other organizations. Instead they can rely on BizTalk Services for all that.  The following picture might help to clarify my point.

 

 

Ok, back to the code

The process of implementing duplex services using BizTalk Services is very similar to the process we follow for traditional WCF services. Let’s take the following duplex contract as an example.

[ServiceContract(CallbackContract= typeof(IComplexEchoCallback))]

public interface IComplexEcho

{

[
OperationContract(IsOneWay=true)]void Echo(string msg);

}

[
ServiceContract]

public interface IComplexEchoCallback

{

[
OperationContract(IsOneWay=true)] void InvalidMessage(string msg);

}

 

In the service implementation we use WS-Addressing to get the BizTalk Services endpoint associated with the callback.

[ServiceBehavior(Namespace = "http://samples.microsoft.com/ServiceModel/Relay/")]

public class ComplexEchoService: IComplexEcho

{

public void Echo(string msg)

{

  if (msg.Contains("error"))

  {

   OperationContext.Current.OutgoingMessageHeaders.To = OperationContext.Current.IncomingMessageHeaders.ReplyTo.Uri;                                                                               

  IComplexEchoCallback callback = OperationContext.Current.GetCallbackChannel<IComplexEchoCallback>();

  callback.InvalidMessage(msg);

  }

 else

 Console.WriteLine(msg);

}

}

 

The configuration file associated with the host application declares two services endpoints: one for the interactions with BizTalk Services and one for obtaining the metadata associated with the service.

<configuration>

<system.serviceModel>

<bindings>

<!-- Application Binding -->

<relayBinding>

<binding name="default" connectionMode="RelayedDuplex"/>

</relayBinding>

</bindings>

<behaviors>

<serviceBehaviors>

<behavior name="ComplexEchoServiceBehavior">

<serviceMetadata httpGetEnabled="True"/>

</behavior>

</serviceBehaviors>

</behaviors>

<services>

<!-- Application Service -->

<service name="service.ComplexEchoService" behaviorConfiguration="ComplexEchoServiceBehavior">

<host>

<baseAddresses>

<add baseAddress="http://myserver:port/EchoService"/>

</baseAddresses> </host>

<endpoint name="RelayEndpoint"

contract="service.IComplexEcho"

binding="relayBinding"

bindingConfiguration="default" address="" />

<endpoint name="MtdEndpoint"

contract="IMetadataExchange"

binding="mexHttpBinding" />

</service>

</services> </system.serviceModel>

</configuration>

 

The host application of the WCF service uses the CardSpace token provider to communicate with BizTalk Services; so before you run this sample you need to set up the corresponding CardSpace cards

CardSpaceTokenProvider tokenProvider = new CardSpaceTokenProvider();

string userName = tokenProvider.GetUserName();

Uri address = new Uri(String.Format("sb://{0}/services/{1}/EchoService/", RelayBinding.DefaultRelayHostName, userName));

ServiceHost host = new ServiceHost(typeof(service.ComplexEchoService), address);

host.Description.Endpoints[0].Behaviors.Add(tokenProvider);

host.Open();

Console.WriteLine("Service address: " + address);

Console.WriteLine("Press [Enter] to exit");

Console.ReadLine();

host.Close();

 

The client implementation is also relatively simple, as you can see in the following code and very similar to traditional WCF duplex clients. As you might notice, we use WS-Addressing to set the callback (ReplyTo) address to a BizTalk Services specific endpoint.

public class CallbackHandler : IComplexEchoCallback

{

public void InvalidMessage(string msg) //callback operation....

{

Console.WriteLine(msg);

}

}

 

class Program

{

static void Main(string[] args)

{

Test();

}

private static void Test()

{

CardSpaceTokenProvider tokenProvider = new CardSpaceTokenProvider();

string userName = tokenProvider.GetUserName();

string serviceUserName = "jesusmrv";

Uri clientUri = new Uri(String.Format("sb://{0}/services/{1}/client/", RelayBinding.DefaultRelayHostName, userName));

Uri serviceUri = new Uri(String.Format("sb://{0}/services/{1}/EchoService/", RelayBinding.DefaultRelayHostName, serviceUserName));

InstanceContext context = new InstanceContext(new CallbackHandler());

RelayBinding binding = new RelayBinding();

binding.ClientBaseAddress = clientUri;

binding.ConnectionMode =
RelayConnectionMode.RelayedDuplex;

EndpointAddress address = new EndpointAddress(serviceUri);

ComplexEchoClient proxy = new ComplexEchoClient(context, binding, address);using (new OperationContextScope((IContextChannel)proxy.InnerChannel))

{

OperationContext.Current.OutgoingMessageHeaders.ReplyTo = ((IClientChannel)proxy.InnerChannel).LocalAddress;

proxy.Echo("error msg1");

}

Console.ReadLine();

}

}

}

 

The key thing to notice is that the neither the service nor the client has to be terribly concerned with the security and communication infrastructure of the solution which are delegated on BizTalk Services instead. Although the example is very simple it might give you an idea of the different messaging scenarios you can implement using BizTalk Services. The complete source code can be downloaded from here…

1 Comment

Comments have been disabled for this content.