Friday, August 1, 2014

Using Non-Serializable Classes or Types in an Orchestration

BizTalk is entirely Stateless. This is achieved by using Persistence Points. In case of any failure during the processing of an Orchestration (for e.g.: power failure or Server Restart etc) BizTalk Server will continue to restart the Orchestration from the last Persistence Point.

Details about the Persistence points will be Stored in BizTalk SQL Server Database by serializing all the data.

Hence Non-Serializable Classes or Types cannot be used directly in Orchestrations.

Don’t worry, we can use them in orchestration with an Atomic Scope, because persistence does not happen within an Atomic scope. The persistence point is created only when the scope completes its execution as it’s an All-or-None scope. So, we can use Non-Serializable Classes or Types inside Atomic Scopes in an Orchestration.

Consider the below Sample:

1. Create a new BizTalk Project and add any dummy Schema.
2. Create a new Orchestration and add a receive shape to receive the message of the Type Schema1 which is created in Step1.

3. Create two variables of types System.Xml.XmlDocument and System.Xml.XmlNode

4. Now add an Expression shape to the orchestration and add code to extract a node from the incoming message and assign that to the variable you created in step3.

5. Try to build the solution. You end up with an error as shown below.

Error 1 a non-serializable object type ‘System.Xml.XmlNode xmlnode’ can only be declared within an atomic scope or service.

6. To resolve this, make the following changes to the solution.

     i. Click on the white space of the Orchestration and make the Transaction Type of the          Orchestration to Long Running.



     ii. Add a Scope Shape and set the Transaction Type of the Scope to Atomic and move            the Expression shape inside the Atomic Scope.
     iii. Move the xmlnode Variable inside the Atomic Scope.


7. Now build the solution. It should work without any errors.

This is just an example. Although this approach is useful, this should be avoided for performance reasons. Alternatives such as XPaths should be considered.

Modify BizTalk Message using C# or External DLL in Orchestration

In many situations, the Mapper available with BizTalk Server or XPath functions might not be sufficient to construct the Required Message in BizTalk Server.

In these scenarios, we can use an external library and construct the message there using C# code.

Scenario:

You have a schema in your BizTalk Project. You receive a message in a receive folder and pass this message to an External Library, update the message and send it back to BizTalk. Save the updated message to a new location.

Solution:

There are two possible ways of doing this:

Option 1: Create an equivalent class file for the Schema and pass the message as class object to the External DLL

Option 2: Pass the message contents as an XML Document to the External DLL and modify the message using XMLDocument, XLinq or any other technique.

Option 1:

1. Create a new BizTalk Project and add a Sample schema Schema1 as shown below.


2. Use the XSD.EXE utility to convert the schema created above into a serializable class. For this, Go to Visual Studio Command Prompt and give the following Command at the directory where Schema is located.

XSD Schema1.xsd /c /o:c:\

Note: Refer this MSDN article for more details on xsd.exe

3. Create a Class Library Project and add the above class file to the Project. Now we have an equivalent class file for the schema.

4. Create a Static method in the Class that updates the Received Object and sends it back using C #as shown below.


5. Build it and add a reference of this class library to the BizTalk Project.

6. Add an orchestration to the BizTalk Project and create two messages of the Type Schema1

7. Add a Receive Shape and Message Constructor shape and a send shape and complete the orchestration as shown below.


8. Add the below code in the Message assignment shape.

Message_2 = ClassLib.Root.GetClassReference(Message_1);

9. This will call the GetClassReference and the Message Message_1 will be automatically serialized into the class Object. Within the method, schema elements and attributes can be accessed just like class properties.

10. To Test this project, deploy both BizTalk project and Class Library to GAC and put an input file, you will see that the values are updated.

Option 2:

The same can also be achieved by passing the Message Contents as an XML object as given below.

Variable_1 = Message_1;
Variable_1.LoadXml(ClassLib.Root.GetClassReferenceUsingXML(Variable_1.OuterXml));
Message_3 = Variable_1;

Note: Variable_1 is of tpye XMLDocument.

Now you should have a method in the External Library that modifies the message using XML Operations. A sample is given below.


While testing schemas with more than 50 Elements, it has been found out that using XMLDocument to modify the Contents (Option 2) was very much faster than using Class Objects (Option 1).

How to Send & Receive Custom Headers from a WCF Service in Orchestration?

In many practical scenarios, Headers of the WCF Message are used to Establish Session / Send some sensitive / routing information. Here I will show you how to Send and Receive data through Custom Headers from a WCF Service.

Scenario:

Orchestration adds Header and Sends to the Service -> Service Receives the Header and writes to EventLog -> Service adds and outbound header and sends back to Orchestration -> Orchestration Receives the Header

1. Create a Sample WCF Service that gets the value from the Incoming Message and adds an outbound header to the outgoing message. Sample code is given below.

public string GetHeaderValue(string HeaderName, string URI)
{
// Receive Inbound Header

string val = OperationContext.Current.IncomingMessageHeaders.GetHeader(HeaderName, URI);
EventLog.WriteEntry(“Received Header”, “Header Value: ” + val);

// Send Outbound Header
MessageHeader header = MessageHeader.CreateHeader(“Test”,”Test.com”,”TestValue”);
OperationContext.Current.OutgoingMessageHeaders.Add(header);

return val;
}

2. Deploy the Service and Consume it in a BizTalk Project. It creates input message schema, orchestration, output message schema, port type and Binding Files.

3. Create three new messages in the Orchestration as shown below .



Let Message_1 and Message_2 represent Input Message Schema and Message_3 represent Output message Schema. [i.e. Message_1 and Message_2 both are referring to same schema]

4. Create a Receive Shape, set the Message property to Message_1, activate to True

5. Add a Construct message shape, set the Message Constructed property to Message_2. We pass header message to the Service by using the property (WCF.OutboundCustomHeaders). Add the following code in the Message Assignment shape.

Message_2 = Message_1;
Message_2(WCF.OutboundCustomHeaders) = @”From Clietn”;

Resulting Orchestration should be like below


Header has been added to the message which will be passed to the Server.

6. Add a send shape, and set the Message property to Message_2.

7. Add a port to the Orchestration and set the port type to the existing port type which is created automatically while consuming the Service.

8. Join the Send shape with the receive port of Service. Resulting orchestration should be like below


9. Add a receive shape and set the Message Property to Message_3 and connect the Response port of the Service with the Send shape.


10. Create a string variable and add an expression shape to extract the Headers that the service sent using the property

Variable_1 = Message_3(WCF.InboundHeaders);
System.Diagnostics.EventLog.WriteEntry(“InBound Headers”, “Received InBound Headers: ” + Variable_1);

11. Now add a Send Shape, Receive and Send ports and complete the Orchestration


12. Deploy the Service and place the below file in the input folder.

<ns0:GetHeaderValue xmlns:ns0=”http://tempuri.org/“>
<ns0:HeaderName>FromClient</ns0:HeaderName>
<ns0:URI>FromClient.com</ns0:URI>
</ns0:GetHeaderValue>

Note: Input will vary depending on the Logic you use.

13. In the event log, it should display two events.


14. One will be created by the service (Step 1) after it received the inbound header) and another one will be Created by the Client Orchestration after it receives the header from the service. (Step 10).

BizTalk Map: Copy Node/Element Name instead of Value from Source Schema

Sometimes it is required to take some decision based on the name of the node (instead of its underlying value).
To get the node name (instead of its value), click on the mapping link -> Properties -> Change the Source Links property value from “Copy text value” to “Copy Name”. This will map the Name of the Node instead of its underlying value.


Hidden Feature of Index Functoid

We all know that how to use Index Functoid to extract values at a particular index in a repeating record. We do this by configuring an index Functoid with two inputs (generally)

  • First Input: The repeating record’s element
  • Second Input: Index value (starts with 1)



However, after reading the full functoid description, I was interested in the highlighted text which says that - index functoid can take >2 parameters depending on the depth of the hierarchy of the source schema. 

To explore more, consider a sample input like below.


Above Input XML has 3 departments HR, Admin & Sales. Now Consider the below simple map.

Test 1:
Functoid inputs: “Name” & “1” 

Output 1:


So, it extracted the First Departments, first Employee.

Test 2:
Let's say, you want to extract the value “HREmployee1”.
Changing your index functoid input to “Name” & “2” will not give you a result. This is the trick. You should extract the first element of second employee record of first department.
Input: “Name”, “1”, “2”

Output 2:
You get “HREmployee1”


Test 3:
Let's say, you want to extract the value “AdminEmployee2”.
Input should be: “Name”,1,3,2 (2 is for 2nd department)


Output 3:



One way to easily understand this is to look at the XSLT generated. 

This would be helpful to give you an idea on how to extract hierarchical values from source using Index Functoid.

Storing the Repeating Records in an Array

Here we will see how to store the value of Repeating Records into an Array.

Problem:

Assume that you have an Employees schema and input message which has multiple Employee Records:



From the above input message, you need to find out the Employee record with highest salary. For example: from the above sample message, we want to map 3rd record (having the highest salary of 9000) from source to target.

Solutions:

Below are the available approaches to get this done:

1. Many people generally go with XSLT
2. Loop through the Input message, find and map only that employee who is having highest salary.

Lets talk about option 2 in detail and see how to achieve it.

Ø  Connect the Salary to a Concatenation Functoid and give a delimiter character which doesn’t occur in the input message.



Ø  Connect the output of the Concatenation Functoid to a Cumulative Concatenate Functoid



Ø  Now if you see the output of the above two Functoid, we get the below string:

5000~3000~9000~1000~

Ø  This is the salary of each Employee record, separated by a delimiting character.

Apply C# script to
·        Split the above string into an Array
·        Sort the Array
·        Find the highest Salary.

Ø  Connect the output of the above two Functoids to a Scripting Functoid and Use a small script to execute the steps a,b,c.



Ø  The output of the above script will give you a value of 9000, which is the highest salary in the input schema.

Ø  Now use Logical Equal Functoid to connect the output of the above script and Salary element of Input Schema and Connect to the Employee Record of Target Schema.



Ø  Now connect each element in Source to Target.



Now if you test the above map with the input message (at the top of this post), you get only one Employee in the output whose Salary is the highest.



NoteThe above mentioned technique has the limitation that the delimiting character used in Step-1 should not occur in the Input element. Else, C# script will wrongly interpret the data.

In such a case, you can Loop through each repeating record using XSLT and add those items into an array. Refer my previous blog for more details: Calling C# code from XSLT

Calling C# code from XSLT

When you do complex mapping especially with EDI / HL7 Schemas, we might not be able to achieve the desired mapping using out of box functoids. In such cases, we go for using Inline XSLT / Inline XSLT Call Template.
While using inline XSLT, there are some tasks which can be complex to develop using XSLT.
For example, what if I want to increment a variable by 2, for each input Record and map the resulting value to a Target element? In XSLT, we don’t have an option of using x=x+2.
In these cases, we can combine C# and XSLT to achieve the desired output.
Lets look at the sample example:
1. Create a Global Variable in a Scripting Functoid and write a method to increment the variable by 2, for each method call.

2. Leave the scripting Functoid as it is. It is not required to connect this to any input/output node.
3. Now place another scripting Functoid from Roolbox and select Inline XSLT Call Template and add your XSLT.
4. In order to call the above C# method from XSLT and get the incremented value, use the below line of code.
<xsl:variable name=”var:counter” select=”userCSharp:IncrementAndReturn()” />

5. Complete XSLT will look like below.
<xsl:template name=”MyXsltConcatTemplate”>
<xsl:for-each select=”Employees/Employee”>
<xsl:variable name=”var:counter” select=”userCSharp:IncrementAndReturn()” />
<BatchNumber>
<xsl:value-of select=”$var:counter” />
</BatchNumber>
</xsl:for-each>
</xsl:template>

6. Completed map will look like below

This way we can leverage C# features and combine it with the flexibility of XSLT and get the desired output.