Friday, January 21, 2011

Untyped Messages and WCF Services in a real scenario

Context:


This project was my first big Biztalk experience. It started more than two years ago (is still in Biztalk 2006 R2) and most of the work was made based on pre-conceived ideas of what was good, what was easy, what was trustable.
The project kept on growing and at a certain point the desire to trash it all and restart was too strong. This is an example of how to slowly modify a monster-like orchestration. The images and names aren’t always the same because they are not from a case-study, they were all taken from a real project. It consisted of several orchestrations and this post was made when each one of them was in a different stage of transformation so that all situations are represented.


In this project we had to deal with a bunch of different XML files, different types, different schedules, and, worst of all, different actions on the destination server.

Transport properties


We could make this by using maps on the send port, but the tracking of the messages was critical so we needed to keep track of the message on every step of the journey. So, an orchestration was the choice.

To reunite everything, the receive port that collects them (from FTP, SAP idocs, etc.) is the entry of the orchestration. The Message schema in the orchestration is System.Xml.XmlDocument so all schemas are accepted with no distinction.
A Decide component help us creating the basic structure for it, with a lot of conditions of type
OriginalMessage(BTS.MessageType) == http://Company/Schemas/BusinessPartnerActivityTypes#ActivityTypes

and a two-way destination port prepared for send/receive schemas of type System.Xml.XmlDocument, we could make it by repeating a lot of components.

For each flow we make

1. Transform Xml (Received message) to original schema
FCBusinessPartnerActivityTypes = OriginalMessage;


2. Map original schema to service schema
Transform Map


3. Transform ServiceSchema to Xml (port schema)
XmlMessage = SMUVASActivityType;


4. Send to Service

5. Receive Response

6. And after some flows made the general picture would be something like

messy orchestration


How to make it in a lighter way?



The first step is to remove the transformation.

1. Declare a string variable for the map, called mapName

1.1. Use an expression editor to select the map based on the message type

1.2. Use the Fully Qualified Name of the map

mapName="";
if(OriginalMessage(BTS.MessageType) == "http://Company/Schemas/OrderTypes#OrderTypes"){ mapName="Company.Biztalk.SmuasCommercialModule.Messaging.map_FCOrderTypes_to_SMUVASOrderTypes";
}
if(OriginalMessage(BTS.MessageType) == "http://Company/Schemas/OrderStatus#OrderStatus"){
mapName="Company.Biztalk.SmuasCommercialModule.Messaging.map_FCOrderStatus_to_SMUVASOrderStatus";
}


2. Then in a message assignment use the transform method.

mapSystemType = System.Type.GetType(mapName);
transform(XmlMessage) = mapSystemType(OriginalMessage);


3. The orchestration will be much simpler.

medium mess orchestration


The next optimization is to remove the multiple actions.


At the if that defines the map, you can also define the action. Something like

if(OriginalMessage(BTS.MessageType) == "http://Company/Schemas/Banks#Banks"){
mapName="Company.Biztalk.SmuasFinancialModule.Messaging.map_FCBanks_to_SMUVASBanks"; action="http://SmuAs/Services/BackendServices/CommonBackendSyncService/ICommonBackendSyncService/SetBankList";
}


And when the request message is created, give it the correspondent action.

mapSystemType = System.Type.GetType(mapName);
transform(RequestMessage) = mapSystemType(OriginalMessage);
RequestMessage(WCF.Action)= action;


The look of the orchestration is much lighter and pleasant to work with.
Simple orchestration

1 comment:

Leonid Ganeline said...

I will defenitely use this in my orchestrations.
Great and elegant solution!
Thanks!