Search This Blog

Friday 9 June 2023

Sending Email to Multiple recipients using PowerShell

Hi All, 

Below is the working code to Send emails to Multiple recipients using PowerShell.


[STRING]$PSEmailServer = "YourSMTPServerIPOrName"

[STRING]$Subject = "YourSubject"

[STRING]$From = "From@from.com"

[STRING[]]$EmailTo = "To1@To.com", "To2@To.com"

[STRING]$mailBodyPT = "Your Mail Body Goes Here"

[STRING]$HTMLmessage = @"

<font color=""black"" face=""Arial"" size=""3"">

<h1 style='font-family:arial;'><b>YourHeader</b></h1>

<p style='font: .8em ""Lucida Grande"", Tahoma, Arial, Helvetica, sans-serif;'>$mailTextReportPT</p>

<style type=""text/css"">body{font: .8em ""Lucida Grande"", Tahoma, Arial, Helvetica, sans-serif;}

ol{margin:0;}

table{width:80%;}

thead{}

thead th{font-size:120%;text-align:left;}

th{border-bottom:2px solid rgb(79,129,189);border-top:2px solid rgb(79,129,189);padding-bottom:10px;padding-top:10px;}

tr{padding:10px 10px 10px 10px;border:none;}

#middle{background-color:#900;}

</style>

<body BGCOLOR=""white"">

$mailBodyPT

</body>

"@


Send-MailMessage -From $From -To $EmailTo -Subject $Subject -Body $HTMLmessage -BodyAsHtml -SmtpServer $PSEmailServer

Thursday 8 December 2022

Reading the value from SSO within BizTalk Orchestration & Map

Hi there,

Below is the Helper library project that I have created to access the values from the SSO in BizTalk. 

ConfigurationPropertyBag.cs:- 

using Microsoft.BizTalk.SSOClient.Interop;

namespace SAT.Common.SSOClient

public class ConfigurationPropertyBag : IPropertyBag
    {
        private HybridDictionary properties;
        internal ConfigurationPropertyBag()
        {
            properties = new HybridDictionary();
        }
        public void Read(string propName, out object ptrVar, int errLog)
        {
            ptrVar = properties[propName];
        }
        public void Write(string propName, ref object ptrVar)
        {
            properties.Add(propName, ptrVar);
        }
        public bool Contains(string key)
        {
            return properties.Contains(key);
        }
        public void Remove(string key)
        {
            properties.Remove(key);
        }
    }

}

SSOClient.cs:-

using System;

using Microsoft.BizTalk.SSOClient.Interop;

namespace SAT.Common.SSOClient

{

    public class SSOClient

    {

        private string idenifierGUID = "ConfigProperties";

        /// <summary>

        /// Read method helps get configuration data

        /// </summary>        

        /// <param name="appName">The name of the affiliate application to represent the configuration container to access</param>

        /// <param name="propName">The property name to read</param>

        /// <returns>

        ///  The value of the property stored in the given affiliate application of this component.

        /// </returns>

        public string Read(string appName, string propName)

        {

            try

            {

                SSOConfigStore ssoStore = new SSOConfigStore();

                ConfigurationPropertyBag appMgmtBag = new ConfigurationPropertyBag();

                ((ISSOConfigStore)ssoStore).GetConfigInfo(appName, idenifierGUID, SSOFlag.SSO_FLAG_RUNTIME, (IPropertyBag)appMgmtBag);

                object propertyValue = null;

                appMgmtBag.Read(propName, out propertyValue, 0);

                return (string)propertyValue;

            }

            catch (Exception e)

            {

                throw e;

            }

        }

    }

} 

SSOInstanceClient.cs:-

namespace SAT.Common.SSOClient

{

    /// <summary>

    /// This class is created for Map purposes.

    /// </summary>

    public class SSOInstanceClient

    {

        public string Read(string appName, string propName)

        {

            var SSOClientobj = new SSOClient();


            return SSOClientobj.Read(appName, propName);

        }

    }

} 

SSOStaticClient.cs:-

using System;

namespace SAT.Common.SSOClient

{

    /// <summary>

    /// This class is created for Orchestration purposes. The class needs to be Serialized

    /// </summary>

    [Serializable]

    public static class SSOStaticClient

    {

        public static string Read(string appName, string propName)

        {

            var SSOClientobj = new SSOClient();

            return SSOClientobj.Read(appName, propName);

        }

    }

}

Usage in the Map:- 

Usage in the Orchestration:- 

strKeyValue = SAT.Common.SSOClient.SSOStaticClient.Read("YourSSOAppName", "YourKey")

Have a great day.

Newly added Distinguished field is not available after re-deployment in BizTalk

Hi there, 

Recently we have come across an issue after deploying a change to the Production. I have added a distinguished field to the existing schema and deployed it to the Production after it was tested on the QA. Everything was perfectly fine in the QA and but it was giving the below error in the orchestration while trying to access the newly added distinguished field in the orchestration.

When we checked the schemas and distinguished fields on the schema in the admin console, we could see the schema was correct.

We used the Azure CI/CD pipeline to deploy to production. It deletes the application and re-adds it but still, the dll's were in the memory of the host instance.

Error:-

Microsoft.XLANGs.RuntimeTypes.RuntimeInternalErrorException   at Microsoft.XLANGs.Core.Part.GetDFDef(String dottedPath) at Microsoft.XLANGs.Core.XSDPart.GetDistinguishedField(String dottedPath)

Cause and Resolution:-

The issue was due to the Host instance that was not restarted. We have restarted the host instances which fixed the issue.

Have a great day.

Thursday 25 February 2021

BizTalk Orchestration fails to open in Design View rather opens in the xml editor

Hi there, 

Hope you are doing well.

Recently, I have come across a situation where I have installed an MS office update and somehow it corrupted the BizTalk Orchestration Designer. BizTalk Orchestration Designer was not getting displayed in the list of editors as shown below. 

When I have opened the BizTalk project file in the XML format, it was showing as below. 

<ItemGroup>

<XLang Include="ProcessOrder.odx">

<TypeName>ProcessOrder</TypeName>

<Namespace>MyProjectNamespace</Namespace>

<SubType>Task</SubType>

</XLang>

</ItemGroup>

For most of the people out there the <SubType>Designer</SubType>  section is shown and once removed it worked as expected but in my case, I don't have <SubType>Designer</SubType> in the project file. 


To solve the problem, I have closed all the opened visual studio instances and ran the below command in the Developer Command prompt for Visual studio and I could see the BizTalk Orchestration designer as shown below. Run the Developer Command prompt for Visual Studio as an administrator.


devenv.exe /ResetSettings

Hope it has solved your problem.

Have a great day.

Monday 30 December 2019

Error while inserting the data to SQL Server from BizTalk WCF-SQL Send Port

Good day all,

When BizTalk is inserting the data into the custom database that you have we might encounter a lot of issues.
The below error is one among many other common issues that we get in non-Production servers.

Error:
System.Data.SqlClient.SqlException (0x80131904): Could not allocate space for object 

'YourTableName'.'YourPrimaryKeyName' in database 'YourDatabaseName' because the 'PRIMARY' filegroup is full. 

Create disk space by deleting unneeded files, dropping objects in the filegroup, adding additional files to the 

filegroup, or setting autogrowth on for existing files in the filegroup.

Server stack trace: 
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndRequest(IAsyncResult result)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.ServiceModel.Channels

Cause:

SQL Server databases have .mdf (PRIMARY data file) and .ldf(log data files). On each database, we can set the Initial Size(in MB) and Autogrowth/ Max size for data and log files on the database.

As the data gets inserted into the database the files grow accordingly. 

Solution:

When the SQL Server database data files are full we encounter the above issue. We need to fix the storage issues on the DB Server.

Friday 20 December 2019

When SFTP send port is Configured with port number different from the port number that SFTP site is configured on.

Hi All,

Hope you are all doing well.

Below is my observation when SFTP send port is configured to run on a different port than Destination SFTP site configured port.

WinSCP.SessionRemoteException: Network error: Connection to "FTPServerIP or FTPDNSName" timed out. ---&gt; WinSCP.SessionRemoteException: The server rejected SFTP connection, but it listens for FTP connections.

Did you want to use FTP protocol instead of SFTP? Prefer using encryption.
   --- End of inner exception stack trace ---

Server stack trace: 
   at WinSCP.SessionLogReader.Read(LogReadFlags flags)
   at WinSCP.ElementLogReader.Read(LogReadFlags flags)
   at WinSCP.SessionElementLogReader.Read(LogReadFlags flags)
   at WinSCP.CustomLogReader.TryWaitForNonEmptyElement(String localName, LogReadFlags flags)
   at WinSCP.CustomLogReader.WaitForGroupAndCreateLogReader()
   at WinSCP.Session.Open(SessionOptions sessionOptions)
   at Microsoft.BizTalk.Adapter.Sftp.SftpConnection.OpenUnderlyingConnection(SftpConnectionProperties connectionProperties)
   at Microsoft.BizTalk.Adapters.CommonHelpers.Connection`3.ConnectionPool`3.GetConnection(T1 connectionProperties, TimeSpan timeout)
   at Microsoft.BizTalk.Adapters.CommonHelpers.Connection`3.GetConnection(T connectionProperties, TimeSpan timeout)
   at Microsoft.BizTalk.Adapter.Sftp.SftpOutputChannel.Send(Message message, TimeSpan timeOut)
   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]&amp; outArgs)
   at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)

Exception rethrown at [0]: 
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndSend(IAsyncResult result)

Exception rethrown at [1]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&amp; msgData, Int32 type)
   at System.ServiceModel.Channels.IOutputChannel.EndSend(IAsyncResult result)
   at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendCallback(IAsyncResult result)

Tuesday 17 December 2019

BizTalk FF Pipeline: The remaining stream has unrecognizable data.

Hi All,

Hope everyone is enjoying the festive season.

Another small article on the error that I have got when I am handling the Flat file message on the receive side.

Error:-
The remaining stream has unrecognizable data and HRESULT:c0c01464 in BizTalk on the
Log Name:      Application
Source:        BizTalk Server
Date:          2019-12-17 10:34:33 AM
Event ID:      5753
Task Category: BizTalk Server
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      YourBizTalkServerName
Description:
A message received by adapter "BiztalkMessagingEngine" on receive location "YourReceiveLocationName" with URI "YourLocationAddress" is suspended.
 Error details: There was a failure executing the receive pipeline: "YourPipelineFullyQualifiedName, YourProjectName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=27a168965285aebe" Source: "Flat file disassembler" Receive Port: "YourReceivePortName" URI: "YourLocationAddress" Reason: The remaining stream has unrecognizable data. 
 MessageId:  {BC21C975-006C-418F-97A5-EAAE7472C0E8}
 InstanceID: {0DA3DA9D-1234-4D0A-B623-68159BF68DDA}
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="BizTalk Server" />
    <EventID Qualifiers="49344">5753</EventID>
    <Level>2</Level>
    <Task>1</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2019-12-17T08:34:33.000000000Z" />
    <EventRecordID>199652</EventRecordID>
    <Channel>Application</Channel>
    <Computer>YourBizTalkServerName</Computer>
    <Security />
  </System>
  <EventData>
    <Data>{BC21C975-006C-418F-97A5-EAAE7472C0E8}</Data>
    <Data>{0DA3DA9D-1234-4D0A-B623-68159BF68DDA}</Data>
    <Data>BiztalkMessagingEngine</Data>
    <Data>Your location address</Data>
    <Data>YourReceiveLocationName</Data>
    <Data>There was a failure executing the receive pipeline: "YourPipelineFullyQualifiedName, SYourProjectName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=27a168965285aebe" Source: "Flat file disassembler" Receive Port: "YourReceivePortName" URI: "YourLocationAddress" Reason: The remaining stream has unrecognizable data.  </Data>
  </EventData>
</Event>

Cause:- In my case, I have a repeating record which is separated with the LF(Line Feed) character, For some reason, the source system has generated the file with an extra LF character after the first record (first line) which is where the problem is. On the Schema, after first LF, the pipeline is expecting a new record. In my case instead of the new data record, there is another LF which is causing the pipeline to fail with the above-mentioned error.

Solution:- Souce System to correct the behaviour

Execute the FFDASM to create the scenario:- Below is the error when I ran FFDASM.
ffdasm.exe yourTestInputFile.FileExtention -bs yourSchema.xsd

HRESULT:        c0c01464


Tuesday 17 September 2019

BizTalk: Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401)

Hi BizTalk Buddies,

Hope you are all doing great. Time for another Article.

As we all know that the BizTalk host can either be 32-bit or 64-bit and our host instances run on those hosts. 

As we might also know, 
Running the FTP adapter, POP3 adapter, and MIME Decoder on 64-bit host instances is not supported. We can only run them on 32-bit host instances.

Errors in the event viewer:-
There was a failure executing the send pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML assembler" Send Port: "sendPortName" URI: "mssql://xxxxServerName//xxxxDBName?" Reason: Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401)


A message sent to adapter "WCF-SQL" on send port "sendPortName" with URI "mssql://xxxxServerName//xxxxDBName?" is suspended. 
 Error details: There was a failure executing the send pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML assembler" Send Port: "xxxYourSendPortName" URI: "mssql://ltvmanchikanti//Insurance_Collections?" Reason: Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401)  
 MessageId:  {934486D4-5F64-4EED-BBE8-E68A5F5DDBA8}
 InstanceID: {C78702BB-4DFE-412B-98F9-AAD347660ACC}


There was a failure executing the response(receive) pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML disassembler" Send Port: "xxxYourSendPortName" URI: "mssql://xxxxServerName//xxxxDBName?" Reason: Loading this assembly would produce a different grant set from other instances. (Exception from HRESULT: 0x80131401)

Reason:- The reason why we are getting the above errors is that our send adapter hander on the port where we get an error is running on a 32-bit host as opposed to 64-bit.

NB: Normally this happens when we use default host(BizTalkServerApplication which might be a 32-bit host) that gets created when BizTalk is installed.

Solution Steps:- 

  • We must create the host with 32-bit only checkbox un-checked as shown below.
  • Create the send/receive handler on the Adapter(in my Case WCF-SQL but the principle is same for other adapters that run on the 64-bit host) that we have experienceing the issue on.
  • Select the adapter handler that is created in the above step as shown below.

Tuesday 27 August 2019

BizTalk WCF-SQL Polling and de-batching on Receive Port(De-batching SQL Data)

Hi BizTalk Buddies,

Hope you are all doing great. Every one of us come across the scenario where we need to poll from the database. When we are polling, we can either can poll the single record at a time and process it or poll multiple records at a time and de-batch using Envelope schema on the receive port and Process the de-batched records individually. Here is a simple article that explains how to poll from the DB and de-batch on the receive port and subscribe to the Debatched Messages.

Below is the Employee Schema(Employee.xsd) that contains the Single Employee.
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://BTS_SQL_Debatch.Employee" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" elementFormDefault="qualified" targetNamespace="http://BTS_SQL_Debatch.Employee" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Employee">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Name" type="xs:string" />
        <xs:element name="ID" type="xs:string" />
        <xs:element name="Salary" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
Below is the Employees Schema(Employees.xsd) that contains multiple employees that are polled from the database. Employee schema is imported to this Schema. Employees Schema has marked as an Envelope and the Body XPath is selected as shown below.
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://BTS_SQL_Debatch.Employees" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns:ns0="http://BTS_SQL_Debatch.Employee" targetNamespace="http://BTS_SQL_Debatch.Employees" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import schemaLocation=".\Employee.xsd" namespace="http://BTS_SQL_Debatch.Employee" />
  <xs:annotation>
    <xs:appinfo>
      <b:schemaInfo is_envelope="yes" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" />
      <b:references>
        <b:reference targetNamespace="http://BTS_SQL_Debatch.Employee" />
      </b:references>
    </xs:appinfo>
  </xs:annotation>
  <xs:element name="Employees">
    <xs:annotation>
      <xs:appinfo>
        <b:recordInfo body_xpath="/*[local-name()='Employees' and namespace-uri()='http://BTS_SQL_Debatch.Employees']" />
      </xs:appinfo>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="ns0:Employee" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Deploy the solution.

Once the solution is been deployed, We need to create One-way WCF-SQL receive Port as shown below.
Port Name:- rcv_Employees
Receive Location Name:- rcv_WCF-SQL_Employees
Type:- WCF-SQL
Receive Pipeline:- XMLReceive

In the Configure section please do the below settings.
Address(URI):- mssql://YourServerName//YourDatabaseName?InboundId=getEmployees
XmlStoredProcedureRootNodeName:- Employees
XmlStoredProcedureRootNodeNamespace:- http://BTS_SQL_Debatch.Employees
InboundOperationType:- "XmlPolling"
PolledDataAvailableStatement:-  SELECT COUNT(1) FROM [dbo].[Employee] WHERE IsPolled IS NULL AND DatetimeBizTalkPolled IS NULL
PollingStatement:-   exec [dbo].[getEmployees]

Rest of the properties you can leave then to the default values.
Save the above configuration. 

Now Create a FILE Sendport that subscribes on BTS.MessageType="http://BTS_SQL_Debatch.Employee#Employee"

Below are the scripts to create the table and the stored proc.

--Table
CREATE TABLE [dbo].[Employee](
[Name] [varchar](50) NULL,
[ID] [int] NULL,
[Salary] [decimal](18, 2) NULL,
[PollingId] [uniqueidentifier] NULL,
[IsPolled] [bit] NULL,
[DatetimeBizTalkPolled] [datetime] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Employee] ([Name], [ID], [Salary], [PollingId], [IsPolled], [DatetimeBizTalkPolled]) VALUES (N'Venu', 123, CAST(10.00 AS Decimal(18, 2)), NULL, NULL, NULL)
GO
INSERT [dbo].[Employee] ([Name], [ID], [Salary], [PollingId], [IsPolled], [DatetimeBizTalkPolled]) VALUES (N'Ravi', 124, CAST(34.00 AS Decimal(18, 2)), NULL, NULL, NULL)
GO
INSERT [dbo].[Employee] ([Name], [ID], [Salary], [PollingId], [IsPolled], [DatetimeBizTalkPolled]) VALUES (N'Raghu', 126, CAST(19.00 AS Decimal(18, 2)), NULL, NULL, NULL)
GO
INSERT [dbo].[Employee] ([Name], [ID], [Salary], [PollingId], [IsPolled], [DatetimeBizTalkPolled]) VALUES (N'Rakesh', 129, CAST(63.00 AS Decimal(18, 2)), NULL, NULL, NULL)
GO

Sunday 4 August 2019

Oracle Client Installation on BizTalk Server 2016

Hello BizTalk Buddies,

It has been a while that since I have written an article. 

Recently, I have had a requirement to upgrade BizTalk from 2010 to 2016. My client is using Oracle Database Adapter extensively in BizTalk Server.

There are good Articles that explain the installation and configuration or ODAC for BizTalk 2016 but I feel that they are not detail enough so it's my attempt to clear the gaps in understanding.

Before you can download the ODAC (Oracle Data Access Components), create an Oracle online account from the below URL.

Once you have created an Oracle account, log in to oracle online and you can navigate to the below URL to download the 32 bit Version of the ODAC.
Accept the License Agreement as shown below.


On the same page navigate down till you spot the 12.1.0.1.0 version of ODAC as shown below.
Logon to the BizTalk Server using either an Administrator's account or the service account that the host instances run on.

Open the command line as an administrator, and navigate to the folder location where you have extracted the downloaded zip file.

In my case, I have downloaded and extracted the file to the below location.
D:\Software\ODAC121010Xcopy_32bit

In the command prompt run the following command if you would like to install to C:\ Drive on the server. Otherwise, change the drive accordingly and run the below command.
D:\Software\Oracle Client\ODAC121010Xcopy_32bit>install.bat all C:\Oracle myhome

Note:- Some checks after the above installation is completed.
1). Double-check that, the Oracle home path is set up properly in System Environment variables.
2). If you are using TNS name aliases, then double-check your file exists in the respective location. In my case, it is in C:\Oracle\network\admin\tnsnames.ora.

Monday 8 October 2018

Windows 10 October 2018 Update (version 1809) issue that is deleting the files

Hi all,

Microsoft October release for Windows 10 has some issues. You might find some missing files after the updated has been done.

Microsoft has officially confirmed that, Windows 10 users across the globe to not update Windows 10 October release(Release date: October 2, 2018) if you have not already updated. Below is the Microsoft URL that confirms the issue.

https://support.microsoft.com/en-us/help/4464619/windows-10-update-history
Below is the Screenshot taken from Microsoft support website.


If you have already updated the patches then don't don't start using the computer and immediately  contact your country Microsoft support number.

Below is the URL for respective country support numbers.

https://support.microsoft.com/en-us/help/4051701/global-customer-service-phone-numbers

Microsoft South Africa Contact Number:- 0860 22 55 67
Microsoft India Contact Numbers:- +91(0)80 4010 3000, 1 800 11 1100, 1 800 102 1100




Wednesday 3 October 2018

Converting CDATA to XML and mapping it to the root node in BizTalk map using XSLT


In one of my recent projects, I’ve come across the requirement where the source system is sending the XML wrapped under the CDATA in string element.  Source system can send its own namespace in the content of the CDATA. I had a requirement to extract the CDATA and change the namespace in the CDATA and map it to the destination schema. Below is the procedure that I’ve followed to achieve the task.
There are 2 things that I have explored as part of this.
1). If the Source system doesn’t provide namespace
2). If Source System provides its own namespace and we need to change the source namespace to the destination namespace.
The Source and destination schemas that I have used to explain the concepts are shown below.
Source Schema CustomerCDATASchema.xsd
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://BizTalkConcepts.CustomerCDATASchema" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" elementFormDefault="qualified" targetNamespace="http://BizTalkConcepts.CustomerCDATASchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Customers">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="CustomersCDATA" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
Destination Schema CustomerXmlSchema.xsd
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://BizTalkConcepts.CustomerXmlSchema" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" elementFormDefault="qualified" targetNamespace="http://BizTalkConcepts.CustomerXmlSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Customers">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Customer">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CustomerId" type="xs:string" />
              <xs:element name="CustomerName" type="xs:string" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
The above requirement can be achieved by using custom XSLT templates.
After Googling and spending some time I have managed to solve the problem.
The sample input message is as shown below.
<ns0:Customers xmlns:ns0="http://BizTalkConcepts.CustomerCDATASchema">
  <ns0:CustomersCDATA><![CDATA[
    <ns0:Customers xmlns:ns0="http://BizTalkConcepts.CustomerCDATASchema">
      <ns0:Customer>
        <ns0:CustomerId>CustomerId_0</ns0:CustomerId>
        <ns0:CustomerName>CustomerName_0</ns0:CustomerName>
      </ns0:Customer>
    </ns0:Customers>]]>
  </ns0:CustomersCDATA>
</ns0:Customers>
The Output that I’m expecting is as shown below. Make observation on the namespaces highlighted.
<ns0:Customers xmlns:ns0="http://BizTalkConcepts.CustomerXmlSchema">
  <ns0:Customer>
    <ns0:CustomerId>CustomerId_0</ns0:CustomerId>
    <ns0:CustomerName>CustomerName_0</ns0:CustomerName>
  </ns0:Customer>
</ns0:Customers>
Create a map CustomerCDATASchema_To_CustomerXmlSchema.btm.
This map takes the CDATA and converts to the XML.
Drag and drop the scripting functiod and select Script type as Inline XSLT Call Template, copy and paste the below code.
1.       If the Source system doesn’t provide namespace
<!-- This Template extracts the CDATA field from the Source and adds the namespace when outputting -->
<xsl:template name="TemplateToExtractCDATAandAddNamespace">
  <xsl:param name="param1" />
  <xsl:variable name="localCustomersCDATA" select="." />
  <xsl:call-template name="search-and-replace">
    <xsl:with-param name="input" select="string($localCustomersCDATA)" />
    <xsl:with-param name="search-string" select="string('&lt;Customers&gt;')" />
    <xsl:with-param name="replace-string" select="string('&lt;Customers xmlns=&quot;http://BizTalkConcepts.CustomerXmlSchema&quot;&gt;')" />
  </xsl:call-template>
</xsl:template>

<!-- This Template replaces the given string with the specified string. -->
<xsl:template name="search-and-replace">
  <xsl:param name="input"/>
  <xsl:param name="search-string"/>
  <xsl:param name="replace-string"/>
  <!-- Find the substring before the search string and store it in a
     variable -->
  <xsl:variable name="temp"
       select="substring-before($input,$search-string)"/>
  <xsl:choose>
    <!-- If $temp is not empty or the input starts with the search
          the string then we know we have to do a replace. This eliminates the
          need to use contains(  ). -->
    <xsl:when test="$temp or starts-with($input,$search-string)">
      <xsl:value-of disable-output-escaping="yes" select="concat($temp,$replace-string)"/>

      <xsl:call-template name="search-and-replace">
        <!-- We eliminate the need to call substring-after
                    by using the length of temp and the search string
                    to extract the remaining string in the recursive
                    call. -->
        <xsl:with-param name="input"
        select="substring($input,string-length($temp)+
                         string-length($search-string)+1)"/>
        <xsl:with-param name="search-string"
             select="$search-string"/>
        <xsl:with-param name="replace-string"
             select="$replace-string"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of disable-output-escaping="yes"  select="$input"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
2.       If Source System provides its own namespace and we need to change the source namespace to the destination namespace.

If the Input that we are getting in the CDATA filed has source namespace that needs to be replaced with the destination namespace then just change the TemplateToExtractCDATAandAddNamespace template to the below shown then it will work. Make an observation to the highlighted section.

<xsl:template name="TemplateToExtractCDATAandAddNamespace">
  <xsl:param name="param1" />
  <xsl:variable name="localCustomersCDATA" select="." />
  <xsl:call-template name="search-and-replace">
    <xsl:with-param name="input" select="string($localCustomersCDATA)" />
    <xsl:with-param name="search-string" select="string(&apos;&quot;http://BizTalkConcepts.CustomerCDATASchema&quot;&apos;)" />
    <xsl:with-param name="replace-string" select="string(&apos;&quot;http://BizTalkConcepts.CustomerXmlSchema&quot;&apos;)" />
  </xsl:call-template>
</xsl:template>

Map the CustomersCDATA field to the Scripting template and the output of the scripting functiod to the root node in the destination as shown below.

NB: Please let me know if this article has helped you. Feel free to ask questions in the comments below if you have any requirements on the map that you are struggling to solve.


Sending Email to Multiple recipients using PowerShell

Hi All,  Below is the working code to Send emails to Multiple recipients using PowerShell. [STRING]$PSEmailServer = "YourSMTPServerIPOr...