@michaelLipscombe 

Entries in Loopback (2)

Friday
May182012

BizTalk WCF Loopback Binding, writing to the context

Yesterday I posted an article about writing a Custom WCF Loopback Binding. I was having trouble getting the properties to be written to the context of the message in BizTalk. The code in question was this block

private Message CreateResponseMessage(Message requestMessage)
{
Message message = Message.CreateMessage(MessageVersion.Default, requestMessage.Headers.Action,
requestMessage.GetReaderAtBodyContents());

if (_connection.ConnectionFactory.Adapter.PreserveProperties)
{
message.Properties.CopyProperties(requestMessage.Properties);
}

return message;
}

I incorrectly assumed the WCF-Custom adapter would promote all properties in the Message.Properties collection. Akshat Sharma came to the rescue and pointed out that

All the ‘things’ that you want to promote using WCF message properties should be inside an IEnumerable of key value pairs: IEnumerable<KeyValuePair<XmlQualifiedName, object>> and this IEnumerable should be a property in your WCF message with name : "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/Promote" or “http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/WriteToContext

So the request message has all the properties that were in the context and if I want to write them back I’ll have to define an IEnumerable of key value pairs. Something like this:

private Message CreateResponseMessage(Message requestMessage)
{
string propertiesToPromoteKey = "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties/WriteToContext";

XmlReader reader = requestMessage.GetReaderAtBodyContents();
Message message = Message.CreateMessage(MessageVersion.Default, requestMessage.Headers.Action, reader);
List<KeyValuePair<XmlQualifiedName, object>> propertiesToPromote = new List<KeyValuePair<XmlQualifiedName, object>>();

if (_connection.ConnectionFactory.Adapter.PreserveProperties)
{
foreach (var property in requestMessage.Properties)
{
if(property.Key.Contains("#"))
{
var keySplit = property.Key.Split('#');
XmlQualifiedName qualifiedName = new XmlQualifiedName(keySplit[1], keySplit[0]);
propertiesToPromote.Add(new KeyValuePair<XmlQualifiedName, object>(qualifiedName, property.Value));
}

}

message.Properties.Add(propertiesToPromoteKey, propertiesToPromote);
}

return message;
}

It also turns out some of the properties in the request message are not known to BizTalk, for example http://schemas.microsoft.com/BizTalk/2003/system-properties#BizTalkMessageID. If you try and promote this property you’ll get this error:

The Messaging Engine failed while executing the inbound map for the response message coming from the destination URL "loopback://" with the Message Type http://MessageType . Details:"Loading property information list by namespace failed or property not found in the list. Verify that the schema is deployed properly. "

If on the other hand you try and write that property to the context (not promoted) you’ll just see this error. Note the absence of any helpful information.

The adapter failed to transmit message going to send port "SndLoopback" with URL "loopback://". It will be retransmitted after the retry interval specified for this Send Port. Details:"Exception of type 'Microsoft.BizTalk.Message.Interop.BTSException' was thrown.".

So basically you’ll want to exclude all properties in these namespaces.

http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties
http://schemas.microsoft.com/BizTalk/2003/messageagent-properties
http://schemas.microsoft.com/BizTalk/2003/messagetracking-properties
http://schemas.microsoft.com/BizTalk/2003/system-properties

Most of those properties BizTalk will deal with when the response is published. From system-properties I only really care about the Operation as that will be handy to preserve on a looped message especially if it goes out to another WCF send port. Most of the properties that are of value are going to be from adapters like FILE.ReceivedFileName or MQSeries.BizTalk_CorrelationID and they should work.

Thursday
May172012

BizTalk WCF Loopback Binding

The original BizTalk Loopback Adapter developed by  Gregory Van de Wiele has been around forever and I’m sure lots of places are using. The need for the loop back is usually related to envelopes as the debatching component is the XmlReceive Pipeline or more accurately the Xml Disassembler. If the schema has the Envelope flag set to YES it will go looking for the Body XPath field that tells it how to debatch the message.

A lot of times you can debatch the envelope as you receive the message but sometimes you end up creating the enveloped message in BizTalk. This forces you to try and call the Xml Disassembler someway or develop your own debatching component. As Gregory points out in his post there are a few ways to do this.

1. Using an Adapter to write the message out and back (MSMQ, FILE)

2. HTTP Loopback (page that just echoes back)

3. Execute a Receive Pipeline from within an Orchestration

4. The good old Loopback Adapter

5. .NET component

We have a new client that has a lot of envelop schemas and their solution to date has been to use a folder/FILE adapter to loop them out and back so the XMLReceive can be executed. I’m not a big fan of this approach; you end up with this complicated folder structure that you’ll have to manage if you have a lot of different envelope messages. You’ll have 2 extra ports to support plus the performance/latency that it adds.

Calling the pipeline in an orchestration is a good option but it complicates the orchestrations with loops and expressions. You’ll also end up repeating the “code” for each message type/orchestration. Perhaps you could get clever and built a generic debatching orchestration but for my money (it’s their money actually) I’d rather use the Loopback adapter.

A loopback adapter is simply a two way send adapter that simply returns a copy of the outbound message. It’s gives you two opportunities to execute pipelines and maps on the way out and when it comes back in without the overhead of some kind of repository. One negative of the loopback adapter is that it’s a solicit response send port. You can’t bind a one way logical port in an orchestration to the send operation of a two way. So you’ll have to use content based routing (CBR) if an orchestration constructs the envelope.

Gregory’s version was developed in 2004 using .NET 1.1 which obviously predates WCF and to use it today with BizTalk 2010 you’d have to install .NET framework 1.1 which I don’t want to do. It has been a while since I’ve used a loopback so I searched around for an updated version and didn’t find anything. 

The WCF-Custom adapter lets you plug in your own bindings and behaviors so effectively letting you create a custom adapter. I’ve written adapters before using the Adapter Framework but not using the WCF LOB SDK. Hidden away in the SDK is an excellent sample EchoAdapter that implements receive and outbound functionality. I found it very helpful so worth checking out.

The binding only supports a solicit response send port and the message has to be well-formed XML otherwise it will splat. Most of the code is plumbing, the method that loops back our messages is this guy:

private Message CreateResponseMessage(Message requestMessage)
{
Message message = Message.CreateMessage(MessageVersion.Default, requestMessage.Headers.Action,
requestMessage.GetReaderAtBodyContents());

if (_connection.ConnectionFactory.Adapter.PreserveProperties)
{
message.Properties.CopyProperties(requestMessage.Properties);
}

return message;
}
 
It just reads the request message, creates a copy and checks for a property called preserveProperties (you set this on the binding) which tells it to copy all the properties from the request message to the response. As it’s using an XmlReader it the body contains a flat file or anything other then XML you’ll make it angry. There are a couple of ways to read the message body so if you want this to work with say an EDI message I’m sure you could get it to work.
 
image
 
The Address or URI is simply “loopback://” and you must provide an action although it doesn’t care what it is.

image

On the Binding tab there’s only one property preserveProperties which instructs the adapter to copy all the promoted properties to the response message. At the time of writing this post I was having troubles getting this working. I’m sure there is another step or component (perhaps a behavior) that I’m missing. I’ll update this post once I figure this out.

Update

To install it just build and GAC the assembly and insert the config settings below into your .NET 4.0 machine.config and you’re away.

<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="loopbackAdapter"
type="LoopbackAdapter.LoopbackAdapterBindingElementExtension, LoopbackAdapter,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=a702dd707b910e02"
/>
</bindingElementExtensions>
<bindingExtensions>
<add name="loopbackAdapterBinding" type="LoopbackAdapter.LoopbackAdapterBindingCollectionElement,LoopbackAdapter,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=a702dd707b910e02"
/>
</bindingExtensions>
</extensions>
</system.serviceModel>

 

The source code for the loopback binding can be downloaded here. Testing is your responsibility, no guarantees, code as is.