Decouple BizTalk Transformation logic From The BizTalk Solution.
Need a BizTalk solution which has no map(Read .btp file) and it still does the transformation, READ ON...... This article speaks of using an external XSL file to achieve transformation in BizTalk solution. You can visualize this as an equivalent of BizTalk map which is only using a XSL file for the transformation logic except you will not be required to use a actual BizTalk map with this approach. This also means no map or XSL file will be deployed. Advantage with this approach is- If there is a change in the transformation logic just modifying the XSLT on the XSL file placed on physical server location is enough. Which mean without any fresh deployment or change to your VS BizTalk solution you have achieved a new transformation logic in the BizTalk workflow.
You can call this transformation method from your orchestration in a construct with MessageAssignment shape. Think of this construct as construct with transform shape which uses a btp file relying on a custom XSL file for the transformation except in this case you will not have a btp file and a xsl file to deploy. Thus it truly decouples your transformation logic from your BizTalk solution.
How do we do that:
Modify the BTSNTSvc config file and add new appSetting keys for the physical path of XSLT file. This is path where you are going to keep the XSLT file(Or you can use any custom config approach for storing the values, for example SSO MMC).
https://psrathoud.files.wordpress.com/2016/07/configchange.png
https://psrathoud.files.wordpress.com/2016/07/configmanagerobject.png
Create a helper class which will return a XmlDocument after applying the XSLT on the input source xml message.
https://psrathoud.files.wordpress.com/2016/07/transformmethod1.png
We will be leveraging Transform method in our BizTalk helper class which Executes the transform using the input document specified by the XmlReader object and outputs the results to an XmlWriter. The XsltArgumentList provides additional run-time arguments.
public void Transform(XmlReader input, XsltArgumentList arguments, XmlWriter results);
https://psrathoud.files.wordpress.com/2016/07/transformmethod.png
Now we can use an orchestration to call this method in a construct with MessageAssignment shape.
*msgOP_Map = PKS_ExternalBizTalkTransformation.ApplyXSLT.ApplyXSLTToPayload(msgIpToMap, "YourXSLTFile.xsl");
*
Code:
Call to the transform Method(CallXSLT.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace PKS_ExternalBizTalkTransformation
{
public class XSLTTransformation
{
public static XmlDocument ApplyXSLTToPayload(XmlDocument SourceXML, string XSLTFileName)
{
return ApplyXSLT.ApplyXSLTToPayload(SourceXML, XSLTFileName);
}
}
}
ApplyXSLT.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
namespace PKS_ExternalBizTalkTransformation
{
class ApplyXSLT
{
private static string XSLTFilePath = null;
private static Hashtable MyCache = new Hashtable();
private static object xsltLock = new object();
static ApplyXSLT()
{
//BTSSvc file to be updated with the Appsettings information for the XSLT path
XSLTFilePath = ConfigurationManager.AppSettings["POC.XSLTFilePath"];
}
public static XmlDocument ApplyXSLTToPayload(XmlDocument SourceXML, string XSLTFileName)
{
XslCompiledTransform xslt = MyCache[XSLTFileName] as XslCompiledTransform;
if (null == xslt)
{
lock (xsltLock)
{
xslt = MyCache[XSLTFileName] as XslCompiledTransform;
if (null == xslt)
{
string fullPath = Path.Combine(XSLTFilePath, XSLTFileName);
XmlDocument styleSheet = new XmlDocument();
styleSheet.Load(fullPath);
XsltSettings settings = new XsltSettings(true, false);
xslt = new XslCompiledTransform();
xslt.Load(styleSheet, settings, new XmlUrlResolver());
MyCache.Add(XSLTFileName, xslt);
}
}
}
XmlReader XMLReader = new XmlNodeReader(SourceXML);
XmlDocument DestinationOPXML = new XmlDocument();
using (XmlWriter writer = DestinationOPXML.CreateNavigator().AppendChild())
{
xslt.Transform(XMLReader, null, writer);
}
return DestinationOPXML;
}
}
}
Please let me know if you have any questions.
Note:For unit/local testing you will be required to use an app.config to define the XSL path since the BTSNTSvc app settings can be only accessed at BizTalk engine runtime .
App Config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="POC.XSLTFilePath" value="C:\PushpendraPOC\PKS_ExternalXSLT_POC"/>
</appSettings>
</configuration>