Search This Blog

Tuesday 2 October 2018

Copying the root node in the source Schema to the CDATA or String field in destination schema in BizTalk Map


In this article, I would like to share some of my experience on the copying the root/any specific node as CDATA/string to the destination element using in BizTalk Map.
There are 2 options that we have to achieve the above mentioned.
1)      Using C#
2)      Using XSLT(Inline XSLT)
I have used below 2 schemas as an example but you can change them according to your own requirement.
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>
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>
Create a map CustomerXmlSchema_To_CustomerCDATASchema.btm:- In this Map we are getting an XML document as a source and we need to copy the whole document to a CDATA/string element in the destination schema.
  
1) Using C#

Note:-This method used both C# and XSLT capabilities to achieve the required functionality.
Step 1:- Drag and drop the scripting functiod(This node has no mapping to it.) and select Script type to Inline C# and copy-paste the below code in it.
        public string ConvertNodeToXmlString(XPathNodeIterator node)
        {
            node.MoveNext();
            return node.Current.OuterXml;
        }

Step 2:-Add another scripting functiod and select the Script type to Inline XSLT and copy and paste the below code.
<!--This code creates the CustomersCDATA element and calls the ConvertNodeToXmlString(C# method)
to copy the source XML to the CustomersCDATA element in this example. If your elementFormDefault property in the destination schema is set to default or unqualified then you must not use ns0:CustomersCDATA must instead use must CustomersCDATA -->
<xsl:element name="ns0:CustomersCDATA">
  <xsl:value-of select="userCSharp:ConvertNodeToXmlString(.)" />
</xsl:element>

This Scripting functiod need to be mapped to CustomersCDATA element in the destination schema.
The final view of the map looks as shown below.

 2)      Using XSLT
Step 1:- Drag and drop the scripting functiod(This node has no mapping to it.) and select Script type to Inline XSLT and copy-paste the below code in it.

<!--This code creates the CustomersCDATA element to copy the source XML to the CustomersCDATA element in this example. If your elementFormDefault property in the destination schema is set to default or unqualified then you must not use ns0:CustomersCDATA must instead use must CustomersCDATA -->
<xsl:element name="ns0:CustomersCDATA">
  <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
  <xsl:copy-of select="." />
  <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
</xsl:element>

This Scripting functiod need to be mapped to CustomersCDATA element in the destination schema.
The final view of the map looks as shown below.










NB: I hope this article helps people out there. Kindly comment or ask questions if you need mode clarity on this topic.


Thursday 8 March 2018

Promote the received FileName and FileExtension in BizTalk Server Receive location using the Custom Pipeline Component

Hi All,

Hope everyone is doing great. It has been a hectic couple of days with my personal life. I am slowly but surely coming back to normal.

Let's get into the real stuff!!!

It is very common requirement that, BizTalk moves files from FileLocation to another location or one of the following Transport protocols

FILE
FTP
SQL
SMTP
etc...

It is also common that, some systems generate a lot of different types of files(it can be different file formats, file with different content and different fileNames) and dump them all into one folder location.

let's say, we come across the requirement to route the files based on the file name and/or the file Extension.

To achieve the above requirement, we can create 1 receive port per file and change file mask on the receive location accordingly such that routing can be achieved. The problem with this approach is that if there are 10's and 100's of files that needed to be routed to the different destinations based on the file name and/or the file Extension the above solution is not the ideal solution for the problem as it requires 10's and 100's of receive ports and locations created.

Instead, I have written a simple receive pipeline component which is used in a custom pipeline. This pipeline component has the very basic code; it extracts the file name(ReceivedFileName), file extension(ReceivedFileExtension) from the file path and promotes it to the Context.

The pipeline is selected on the receive location as shown below.

As the ReceivedFileName, ReceivedFileExtension is promoted to Context they are available on the send Port filters; this way even if you have 100's of files that need to be routed,1 receive port with 1 receive location solves the problem.

The complete class code is below. You have to generate new GUID's for classID, and PipelineComponent and change it accordingly.

//******========================================================*****

    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [System.Runtime.InteropServices.Guid("89X14D30-191F-4FYC-9EED-057B84144588")]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    public class PromoteFileNameAndExtension
    {
        #region IPersistPropertyBag members
        /// <summary>
        /// Gets class ID of component for usage from unmanaged code.
        /// </summary>
        /// <param name="classid">
        /// Class ID of the component
        /// </param>
        public void GetClassID(out System.Guid classid)
        {
            classid = new System.Guid("1F0CGFB2-2729-43A7-A080-17GH29E9HH85");
        }

        /// <summary>
        /// not implemented
        /// </summary>
        public void InitNew()
        {
        }

        #endregion

        #region IBaseComponent members
        /// <summary>
        /// Name of the component
        /// </summary>
        [Browsable(false)]
        public string Name
        {
            get
            {
                return "PromoteFileNameAndExtension";
            }
        }

        /// <summary>
        /// Version of the component
        /// </summary>
        [Browsable(false)]
        public string Version
        {
            get
            {
                return "1.0";
            }
        }

        /// <summary>
        /// Description of the component
        /// </summary>
        [Browsable(false)]
        public string Description
        {
            get
            {
                return "Extracts the exact FileName, FileExtension and promotes to the context.";
            }
        }
        #endregion

        #region IComponentUI members
        /// <summary>
        /// Component icon to use in BizTalk Editor
        /// </summary>
        [Browsable(false)]
        public IntPtr Icon
        {
            get
            {
                return new System.IntPtr();
            }
        }

        /// <summary>
        /// The Validate method is called by the BizTalk Editor during the build
        /// of a BizTalk project.
        /// </summary>
        /// <param name="obj">An Object containing the configuration properties.</param>
        /// <returns>The IEnumerator enables the caller to enumerate through a collection of strings containing error messages. These error messages appear as compiler error messages. To report successful property validation, the method should return an empty enumerator.</returns>
        public System.Collections.IEnumerator Validate(object obj)
        {
            return null;
        }
        #endregion

        #region IComponent members
        /// <summary>
        /// Implements IComponent.Execute method. This Method extracts the fileName from the complete filePath and promote to ReceivedFileName property in http://abcCompany.Ei.Utils.Schemas.Utils_PropertySchema namespace
        /// </summary>
        /// <param name="pc">Pipeline context</param>
        /// <param name="inmsg">Input message</param>
        /// <returns>Original input message</returns>
        /// <remarks>
        /// IComponent.Execute method is used to initiate
        /// the processing of the message in this pipeline component.
        /// </remarks>
        public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
        {
            try
            {
                //Read the file Name from the Context using the Context Property "ReceivedFileName". This property contains the full path of the file
                string fileName = (string)inmsg.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties");
                if (!string.IsNullOrEmpty(fileName))
                {
                    //Promote the fileName to the Context. Before this you need to create the property Schema with "ReceivedFileName", "ReceivedFileExtension" elements and deployed
                    inmsg.Context.Promote("ReceivedFileName", "http://abcCompany.Ei.Schemas.CustomFiles_PropertySchema", System.IO.Path.GetFileName(fileName));
                    inmsg.Context.Promote("ReceivedFileExtension", "http://abcCompany.Ei.Schemas.CustomFiles_PropertySchema", System.IO.Path.GetExtension(fileName).Replace(".", ""));
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("\n PromoteFileNameAndExtension Exception while writing promoting. Details : " + ex.Message);
                throw ex;
            }

            return inmsg;
        }

        #endregion
    }

//******========================================================*****

Please comment below if you have any queries or don't understand any portion of the code.

Have awesome day guys and girls.

Hope I have helped someone who is new to BizTalk Custom Pipeline Component development.

Thursday 8 February 2018

MSMQ: There are insufficient resources to complete the send operation

MSMQ: There are insufficient resources to complete the send operation

When BizTalk is sending the messages to the MSMQ there are quite a few of error messages that we get to experience under different circumstance. One of them is the following error.


Issue:

There are insufficient resources to complete the send operation.
 For example, this could happen when you are trying to send a large message (message larger than 4095 KB) to a non-transactional queue. Large messages can be sent only to transactional queues.

Happens when:
The above error occurred when BizTalk is trying to send the message out to MSMQ while the Journal Queue's on the BizTalk Box is full.

Resolution:

Clear the below system queues both the Journal Messages  and Transactional deal-letter messages as shown below



Once you clear the messages of the system queues, you can resume the suspended instances then it will go through with no issues.


Note:- I think the above is applicable even for the normal C# or any other applications that write to the MSMQ Queue.


Please comment if you experience any other issues related to this.


Monday 31 July 2017

5). Moving Files From FolderA(In) To FolderB(Out) just by using BizTalk Admin Console(Visual Studio is not required for this)

Open Run Command and type “BTSMMCLauncher.exe” to Open BizTalk Admin Console or you can open from installed programs.
Expand BizTalk Server Administration Tree nodeà Expand BizTalk Group NodeàExpand Applications Node
We should see the application (BizTalk_Tutorials) that we have deployed in the previous article in the application list.
Expand BizTalk_Tutorials application node and you should see all the artefact nodes.

Creating Receive Port, Receive Location and configure FILE Receive Location:-

Receive Port: - Receive Port is a Logical container of one or more receive locations. Receive location is the physical one that really connects to the external system. When the Receive location

Right click on Receive Ports node à Newà One-Way Receive Port
In the Name Textbox give the name to Receive Port as rcv_PurchaseOrders

Note: - We are creating this receive port to receive files from a folder location. The location can be on the Server where BizTalk is installed or the network share location.

Click on Receive Locations Tab on Receive Ports window.
Click on New Button to create a new receive location and in the Name Textbox of Receive location (RL) window give the name as rcv_FILE_PurchaseOrders.
In the Type Dropdown select FILE and Click the Configure Button to Configure our receive location.
In the Receive Folder textbox we need to enter the folder location where we will be receiving the files from. In our Example I have I have following location C:\Tutorials\In\

File Mask: - This is very important filed that we need to configure on RL. It we only want to process files with certain file extension then we specify here.  
Example: - If we want to process only xml files then the mask is *.xml
If we want to process only csv files then the mask is *.csv
If we want to process all types of files then the file mask is *.*
In My example I am dealing with .txt files so I am using *.txt in File Mask.

We are done with Receive Port and Receive Location configuration.

Creating Send port and configuring:-

Send Port (SP): - Send Port is the responsible artifact to subscribe to the messages that are been published to Message Box by the Receive Port. SP subscribes to the messages by using something called SP Filters.  The most commonly used Filters are BTS.MessageType, BTS.ReceivePortName.

RC on Send PortsàNewàStatic One-Way Send Portà
Name the SP as snd_PurchaseOrders à Select FILE in the Transport Type drop downà Click on Configure Buttonà

In the FILE Transport Properties window that opensà set the Destination Folder to C:\Tutorials\Out\ and the File name to %SourceFileName% 

Click on Filters tabà  in the middle of the screen click underneath the Property column and add the BTS.ReceivePortName Context Property and in the value field add the Name of the Receive Port that we have created which is rcv_PurchaseOrders


Note: - By creating filter on Send port we have created subscription on send port. By adding this filter, what we telling send port is that, All the messages that are been published from rcv_PurchaseOrders receive port are subscribed by the snd_PurchaseOrders send port. And sent to the destination folder (C:\Tutorials\Out\) configured on Send port.

Now if you drop any .txt files in the input(C:\Tutorials\In\) folder then the files should appear in the output(C:\Tutorials\Out\) folder.

I know if you have followed just all the steps that i have discussed the files will still be there in the input location. The reason for this is the Receive Location, Send Port are not started yet. Once you start them in right sequence then the files wll be moved to output folder.

Note:- First we need to start Send Ports then only receive ports the reason being, if you start the receive location first; BizTalk can't find the active subscribers at that point in time so it will suspend the messages with the below error.

The published message could not be routed because no subscribers were found. This error occurs if the subscribing orchestration or send port has not been enlisted, or if some of the message properties necessary for subscription evaluation have not been promoted. Please use the Biztalk Administration console to troubleshoot this failure. 

Acronyms used in the article:-

(RC): Right Click
(RL): Receive location
(SP):  Send Port

Monday 24 July 2017

4).Deployment of BizTalk Solutions (Projects) to local BizTalk Admin Console

In this article we shall be discussing how to deploy the BizTalk solution (Collection of Projects) to the BTS Admin Console.

BizTalk Deployments are not that complicated as people think in most of the BizTalk environments.
We will be deploying the solution (that consists of 4 projects) that we have created in the previous article). We haven't created any artifacts in the projects yet but deployment process remains same with or without artifacts.

Visual Studio out of the Box gives us ability to deploy the BizTalk Solutions with very easy steps.

Step1:-Make sure solution (or the selected projects that you want to deploy) builds with no errors.

Right Click on the Solution à Build Solution:  as shown below

Once the Build is successful you will see the success message as shown below.

What does Build Solution Do behind the scenes?
If you come from .NET background you might already know what Building a solution results into.
But for non - .NET buddies below is my explanation what it means by building a solution.

In Visual Studio world below is the application structure that we see

  • We create a solution first (This is the top level place holder of any application that we write).
  • Each solution can have 1 or more Projects(BizTalk Projects, C# class libraries, etc.).
  • Each Project can have 1 or more artifacts (such as Schemas, Maps, Orchestration and Pipelines, etc.)
When we build the whole solution, Visual Studio Compiles all the projects in the Solution and creates some files called dll’s (Dynamics Link Library's). If there are any syntactical errors in any artifact then VS will show us with relevant errors.

Compilation is the process of converting the Source code that we write into Computer (.NET Runtime) understandable format. In BizTalk and .NET world the computer understandable format is MSIL (Microsoft Intermediate Language). Please not be worried if you don’t understand what compilation is and how it works. VS does it all for us when we Build the solution.

Each project in the solution results into a DLL after build is successful. If we have 10 projects in the solution then after build is successful it results into 10 DLL’s.

Step2:- Make sure all the projects in the solution have the Application Name and they are Signing is done as mentioned in the previous article from the properties window of the project.

Step3:- Deploy the solution
Right Click on Solution à Deploy Solution: as shown below.

Once the deployment is successful it will show the success message in output window as shown below.

Verifying the deployment is successful:-
After successful installation and configuration of BTS, we get BizTalk Admin Console Tool to manage BizTalk applications.

Open the BTS admin Console as shown below.
Once you open BTS shows the following window. This is one of the windows that we will mostly be working on in the rest of the tutorials.
Expand àBizTalk Server Administration à BizTalk Group àApplications

You should find our BizTalk_Tutorials Application as shown below.
Extapnd our BizTalk_Tutorials and navigate to Resources then you should see the following screen. The below screen confirms that the application has been successfully deployed to BizTalk Admin Console.


Congratulations you have deployed your first BizTalk application.

Note: - We will see the advanced and complex deployments, Exporting, Importing MSI and binding files and some more complex scenarios in near future articles.

Acronyms used in the article:-

VS: - Visual Studio
BTS:- BizTalk Server


If you have any questions or need more clarity on anything discussed in the article please feel free to comment below.

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...