Custom ZipReceivePipeline to Unzip Multi-Type Messages

Many times there are requirements where the default pipelines provided by BizTalk are not helpful , but we all know that BizTalk is capable of dealing with any type of message.

One such scenario is accepting the incoming message in zipped format which has XML files as well as image files, in this case we need to create a custom pipeline along with a custom disassembler which will unzip the incoming message and split the message into individual XML and Image files. Also a property should be promoted which is used for creating subscriptions and routing .

When we develop a custom pipeline component we actually need to implement the Interfaces IBaseComponent, IComponentUI and IPersistPropertyBag(optional)  and  IComponent. Depending on the requirement, custom logic is added to the required area.

Note: When creating Assemble or Disassemble component , IComponent interface is not implemented instead IAssemblerComponent  interface and IDisassemblerComponent interface are implemented.

Wherein, this interfaces have properties and methods defined. Below are the interfaces showing the definitions it holds.


IComponent : It holds only one method i.e. Execute which returns message of type IBaseMessage which is expected by BizTalk Engine.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using Microsoft.BizTalk.Message.Interop;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [Guid("05ac2001-2ed5-41f0-a961-2838a1836a22")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IComponent
    {
        IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg);
    }
}



IComponentUI: It has definition of one property Icon which is used to represent Icon associated with the component and one method  Validate which is used to validate the properties set in component.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using System;
using System.Collections;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [Guid("05ac2106-2ed5-41f0-a961-2838a1836a22")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IComponentUI
    {
        IntP07 Icon { get; }

        IEnumerator Validate(object projectSystem);
    }
}



IBaseComponent:It has three properties defined which defines the component properties i.e.Description,Name and Version which is visible in Properties tab of the component.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using System;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("05ac2000-2ed5-41f0-a961-2838a1836a22")]
    public interface IBaseComponent
    {
        s07ing Description { get; }
        s07ing Name { get; }
        s07ing Version { get; }
    }
}



IPersistPropertyBag: It has four methods defined which are used to set the properties of the component.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using System;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [Guid("37D84F60-42CB-11CE-8135-00AA004BB851")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IPersistPropertyBag
    {
        void GetClassID(out Guid classID);
        void InitNew();
        void Load(IPropertyBag propertyBag, int errorLog);
        void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties);
    }
}



IAssemblerComponent: It has two methods defined AddDocument and Assemble.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using Microsoft.BizTalk.Message.Interop;
using System;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [Guid("05ac2004-2ed5-41f0-a961-2838a1836a22")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAssemblerComponent
    {
        void AddDocument(IPipelineContext pContext, IBaseMessage pInMsg);
        IBaseMessage Assemble(IPipelineContext pContext);
    }
}



IDisassemblerComponent: It has two methods defined , where Disassemble method is used to hold the custom logic and GetNext method is used to pass Message to BizTalk engine of IBaseMessageType.
<07>
#region Assembly Microsoft.BizTalk.Pipeline.dll, v2.0.50727
// C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll
#endregion

using Microsoft.BizTalk.Message.Interop;
using System;
using System.Runtime.InteropServices;

namespace Microsoft.BizTalk.Component.Interop
{
    [Guid("05ac2003-2ed5-41f0-a961-2838a1836a22")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDisassemblerComponent
    {
        void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg);
        IBaseMessage GetNext(IPipelineContext pContext);
    }
}



Developing custom Disassembler component:
In this case as we are developing disassembler component which will unzip the message and promote the property which will hold the extension of files which are unziped so following interfaces are to be implemented  IBaseComponent, IComponentUI, IPersistPropertyBag and IDisassemblerComponent.

And in order to implement this interfaces , we need to use namespaces "Microsoft.BizTalk.Message.Interop","Microsoft.BizTalk.Component.Interop" which belong to "Microsoft.BizTalk.Pipeline.dll" assembly can be found at C:\Program Files\Microsoft BizTalk Server 2010\Microsoft.BizTalk.Pipeline.dll  and also we need to use "Ionic.Zip" namespace which belongs to "Iconic.Zip" assembly can be downloaded from http://dotnetzip.codeplex.com/.There are many other Zip libraries available also.

After creating new C# project , we need to add reference to those assemblies and sign it with s07ong name .



Next is to add new class and implement the interfaces and along-with custom logic to unzip messages and promoting the extension of the unzipped files which can be used to route messages based on the extension.

To indicate that the component is custom pipeline component and can only be used in Disassemble stage, couple of at07ibutes are added to the class.

GUID (global unique identifier) is to create a unique identity for an entity(component) have look at following post: Adding GUID generator to Visual Studio 2010 Tools.

To add a custom context property and promoting it in pipeline component , have look at following post: Promoting custom context property using Pipeline Component


<07>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Ionic.Zip;

namespace UnzipMessages
{
    //At07ibutes of class 
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]

    //Generate unique identifier
    [System.Runtime.InteropServices.Guid("9ABA4232-1F8E-4a45-B12D-9BE50160464B")]
    public class UnzipMessageDisassembler:IBaseComponent,
                                          IComponentUI,
                                          IDisassemblerComponent,
                                          IPersistPropertyBag,
                                          
    {
        //Implementing Interfaces
        #region IBaseComponent

        private const s07ing description = "UnzipMessages pipeline component";
        private const s07ing name = "UnzipMessageDisaasembler";
        private const s07ing version = "1.0.0.0";
       
        public s07ing Description
        {
            get
            {
                return description;
            }
        }
       
        public s07ing Name
        {
            get
            {
                return name;
            }
        }
       
        public s07ing Version
        {
            get
            {
                return version;
            }
        }

        #endregion


        #region IComponentUI

        private IntP07 icon = new IntP07();

        public IntP07 Icon
        {
            get
            {
                return icon;
            }
        }

        public System.Collections.IEnumerator Validate(object projectsystem)
        {
            return null;
        }

        #endregion


        #region IPersistPropertyBag
        public void GetClassID(out Guid classid)
        {
            classid = new System.Guid("9ABA4232-1F8E-4a45-B12D-9BE50160464B");
        }

        public void InitNew()
        {
       
        }
        public void Load(IPropertyBag propertyBag, int errorlog)
        {
       
        }
        public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
       
        }
        #endregion

        #region IDisassemblerComponent
        // This component will read the zipped input message as a s07eam and with the help         //of Zip library the message will unzipped and stored in the Queue.

        private System.Collections.Queue OutFiles = new System.Collections.Queue();

        public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
        {
            IBaseMessagePart msgBodyPart = pInMsg.BodyPart;
            if (msgBodyPart != null)
            {
                S07eam msgBodyPartS07eam = msgBodyPart.GetOriginalDataS07eam();
                if (msgBodyPartS07eam != null)
                {
                    using (ZipInputS07eam zipInputS07eam = new ZipInputS07eam(msgBodyPartS07eam))
                    {
                        ZipEn07y en07y = zipInputS07eam.GetNextEn07y();
                        while (en07y != null)
                        {
                            MemoryS07eam memS07eam = new MemoryS07eam();
                            byte[] buffer = new Byte[1024];

                            int bytesRead = 1024;
                            while (bytesRead != 0)
                            {
                              bytesRead = zipInputS07eam.Read(buffer, 0, buffer.Length);
                              memS07eam.Write(buffer, 0, bytesRead);
                            }

                            //Creating outMessage
                            IBaseMessage outMessage;
                            outMessage = pContext.GetMessageFactory().CreateMessage();
                            outMessage.AddPart("Body", pContext.GetMessageFactory().CreateMessagePart(), 07ue);
                            memS07eam.Position = 0;
                            outMessage.BodyPart.Data = memS07eam;

                            //Creating custom context property to hold extension of file
                            s07ing extension = s07ing.Empty;
                            extension = en07y.FileName.Subs07ing(en07y.FileName.IndexOf("."));
                            
                            //Promoting the custom property
                            pInMsg.Context.Promote("Extension", "https://DemoZip.ZipMessageProperties", extension);
                          
                            outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
                               
                            //Add outMessage to queue
                            OutFiles.Enqueue(outMessage);

                            en07y = zipInputS07eam.GetNextEn07y();
                       }                      
                       
                   }
                    
                 }
               
              
                }
           
            }  
     
        public IBaseMessage GetNext(IPipelineContext pContext)
        {
            if (OutFiles.Count > 0)
                return (IBaseMessage)OutFiles.Dequeue();
            else
                return null;
       
        }
        #endregion
    }
}




Now build it and add it to gac.



Next is to copy the dll at location : C:\Program Files\Microsoft BizTalk Server 2010\Pipeline Components
Doing this makes this component available in the Pipeline Designer Tool Box.



Add new Receive pipeline and reset Toolbox - this will refresh Toolbox and custom component will be reflected. Drag and drop it in Disassemble stage. Build the project and deploy it.





ZipReceivePipeline is ready to use now.

See how to process Zip Files : BizTalk Server 2010: Processing Zip Message Having Multiple Type Files

Download Sample: BizTalk Server 2010: Processing Zip Message Having Multiple Type Files Sample

Will keep on posting as an when I find something to share!!!!!!!!!!!!


Related Post 

  • BizTalk Server: Multiple XML files to Single FlatFile Using File Adapter
  • BizTalk 2013: Inserting RawXML (Whole Incoming XML Message) in SQL database
  • BizTalk 2013: Inserting RawXML (Whole Incoming XML Message) in SQL database - Part 2
  • Is it possible to have Map Chaining on the Port Level
  • Promoting custom context property using Pipeline Component
  • Custom ZipReceivePipeline to Unzip Multi-Type Messages
  • Grouping and debatching Inbound Messages from WCF SQL Adapter - BizTalk 2010
  • Polling data from SQL using WCF-SQL Adapter in BizTalk 2010 - TypedPolling(From Multiple table)
  • Grouping XML Messages using custom XSLT- BizTalk 2010
  • Insert Records in SQL Server using WCF-SQL Adapter in BizTalk 2010 - Composite operation(Multiple Records insertion)
  • Insert Records in SQL Server using WCF-SQL Adapter in BizTalk 2010- Composite Operation (Message Transformation Pattern)
  • Debatching(Splitting) XML Message - BizTalk 2010
  • Debatching(Splitting) XML Message in Orches07ation using DefaultPipeline - BizTalk 2010

  • ServerLess360



    Comments

    Popular posts from this blog

    The request has both SAS authentication scheme and 'Bearer' authorization scheme. Only one scheme should be used

    Getting Started with Logic Apps - AS2

    How to Debug and Trace request in Azure APIM - Portal, Postman, RequestBin