Hello everyone today I am going to write BizTalk custom pipeline code to unzip file and copy same zip file in local directory then after unzip xml files also route in BizTalk orchestration. There is also an advantage of using biztalk xlangs classes to use context promote value in expression shape of orchestration. In the last of this post you can download complete
source code with an example.
Kindly follows are following steps to achieve to do process a zip file in biztalk orchestration using custom pipeline component-
Before follows all steps, please read- BizTalk Pipeline
1. Open
Microsoft Visual Studio as Administrator user and Click File>New>Project…
In Installed Templates click BizTalk Projects then Empty BizTalk Server Project
and Name as “BizTalkLive.Unzip.Disassemble” and click OK.Before follows all steps, please read- BizTalk Pipeline
2. Now leave every thing as it, we will do later, Now right click on your solution and a new C# class library project name as "BizTalkLive.UnZip" then rename class1 as "UnZip".
3. Add dll reference of Ionic for use unzip method in pipeline disassembler stage and also add reference Microsoft.BizTalk.Pipeline for use pipeline method. In the last of this post you are able to download Ionic.dll or It is open source library, download from some another website.
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
usig Ionic.Zip;
4. Now add following attribute and GUID (it is unique value of across network in the word) You can create your own unique GUID or use already that is already created, just click on Tools menu in VS then click on Create GUI, see the following picture-
{
//Attributes of
class
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
//Generate
unique identifier
[System.Runtime.InteropServices.Guid("F7EA6794-5E97-4E20-9C4B-EA9C3FD10FA9")]
5. Now use interface IBasecomponent, IComponentUI, IDisassemblerComponent, IPersistPropertyBag in UnZip class and also Create two string methods PropertyNamespace and ShemaMessageType respectively for add message type that use in xml file and PropertyNamespace of use promote context message. Both method are used in receive pipeline disassembler stage.
public class UnZip : IBaseComponent, IComponentUI, IDisassemblerComponent, IPersistPropertyBag
{
private string
_ShemaMessageType;
private string
_PropertyNamespace;
public string
ShemaMessageType
{
get
{
return _ShemaMessageType;
}
set
{
_ShemaMessageType = value;
}
}
6. As I understand that you know basic concept of IBasecomponent, IComponentUI, IDisassemblerComponent, IPersistPropertyBag so now come to final point IDisassemblerComponent stage.
public void
Disassemble(IPipelineContext pc, IBaseMessage inmsg)
{
//Microsoft.BizTalk.CAT.BestPractices.Framework.Instrumentation.TraceManager.WorkflowComponent.TraceInfo("TSAUnZipDecode
: Unzip process has started at " + DateTime.Now.ToLongDateString());
Byte[] TextFileBytes = null;
string FileStatus = "0";
string extension = "";
string strReceivePortName = "";
string strReceivedFileName = "";
string _filename = "";
IBaseMessagePart msgBodyPart1 = inmsg.BodyPart;
Stream msgBodyPartStream1 = msgBodyPart1.GetOriginalDataStream();
MemoryStream memStream1 = new MemoryStream();
byte[] buffer1 = new Byte[1024];
int bytesRead1 = 1024;
while (bytesRead1 != 0)
{
bytesRead1 =
msgBodyPartStream1.Read(buffer1, 0, buffer1.Length);
memStream1.Write(buffer1, 0,
bytesRead1);
}
IBaseMessage outMessage1;
outMessage1 =
pc.GetMessageFactory().CreateMessage();
outMessage1.AddPart("Body",
pc.GetMessageFactory().CreateMessagePart(), true);
memStream1.Position = 0L;
outMessage1.BodyPart.Data =
memStream1;
if (this.ShemaMessageType
!= null)
{
outMessage1.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", this.ShemaMessageType);
}
outMessage1.Context.Promote("FileExtension",
PropertyNamespace, ".zip");
IBaseMessageContext context = inmsg.Context;
strReceivePortName = context.Read("ReceivePortName", "http://schemas.microsoft.com/BizTalk/2003/system-properties").ToString();
strReceivedFileName = context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties").ToString();
strReceivedFileName =
strReceivedFileName.Substring(strReceivedFileName.LastIndexOf("\\") + 1);
strReceivedFileName = ((string)strReceivedFileName).Replace(".zip", "");
outMessage1.Context.Promote("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties", strReceivedFileName);
outMessage1.Context.Promote("ReceivePortName", "http://schemas.microsoft.com/BizTalk/2003/system-properties", strReceivePortName);
//outMessage1.Context
= PipelineUtil.CloneMessageContext(inmsg.Context);
OutFiles.Enqueue(outMessage1);
In above code I am using IBaseMessage and IBaseMessageContext interface try to get receive port name and received file name and also add original zip message in Enqueue method of System.Collections.Queue then promote message context FileExtension and MessageType. Basically I am try to store my original zip file in my local folder with help of message routing.
7. Continue following code in Disassemble method to unzip zip file and enqueue xml file in
System.Collections.Queue and also promote message type of xml and some property promotion value too so that we can use it in expression shape of orchestration.
System.Collections.Queue and also promote message type of xml and some property promotion value too so that we can use it in expression shape of orchestration.
IBaseMessagePart msgBodyPart_XML = inmsg.BodyPart;
IBaseMessage outMessage;
if (msgBodyPart_XML != null)
{
Stream msgBodyPartStream = msgBodyPart_XML.GetOriginalDataStream();
msgBodyPartStream.Position =
0L;
if (msgBodyPartStream != null)
{
using (ZipInputStream zipInputStream = new ZipInputStream(msgBodyPartStream))
{
ZipEntry entry =
zipInputStream.GetNextEntry();
while (entry != null)
{
Stream memStream = new MemoryStream();
byte[] buffer = new Byte[4096];
int bytesRead = 4096;
while (bytesRead != 0)
{
bytesRead =
zipInputStream.Read(buffer, 0, buffer.Length);
memStream.Write(buffer, 0, bytesRead);
}
//Creating custom context property to hold extension of file
extension =
entry.FileName.Substring(entry.FileName.IndexOf(".")).ToUpper();
_filename =
entry.FileName.ToString();
if (extension == ".XML")
{
FileStatus = "1";
outMessage =
pc.GetMessageFactory().CreateMessage();
outMessage.AddPart("Body", pc.GetMessageFactory().CreateMessagePart(), true);
memStream.Position = 0L;
outMessage.BodyPart.Data = memStream;
outMessage.Context = PipelineUtil.CloneMessageContext(inmsg.Context);
if (this.ShemaMessageType != null)
{
outMessage.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", this.ShemaMessageType);
}
_filename = ((string)_filename).Replace(".xml", "");
outMessage.Context.Promote("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties", _filename);
outMessage.Context.Promote("FileStatus", PropertyNamespace, FileStatus.ToString());
outMessage.Context.Promote("FileExtension", PropertyNamespace, extension.ToLower());
OutFiles.Enqueue(outMessage);
}
else
{
FileStatus = "0";
//outMessage.Context.Promote("FileStatus",
PropertyNamespace, FileStatus.ToString());
//outMessage.Context.Promote("FileExtension",
PropertyNamespace, extension.ToLower());
}
entry =
zipInputStream.GetNextEntry();
}
}
}
}
}
public IBaseMessage GetNext(IPipelineContext pContext)
{
if (OutFiles.Count > 0)
{
return (IBaseMessage)OutFiles.Dequeue();
}
else
{
return null;
}
}
In above code there is IBaseMessage method GetNext() that Dequeue all message one by one in pipeline so that we can easily route this message either in orchestration or direct in send port.
8. In the last right click on same project BizTalkLive.UnZip then click on Property after click on sign tag and then add new strong name file. Now right click same project and build it.
8. In the last right click on same project BizTalkLive.UnZip then click on Property after click on sign tag and then add new strong name file. Now right click same project and build it.
9. Now go to folder location and go to bin\Debug and installed Ionic and UnZip dll in gac. You can reference how to install dll in gac - Install DLL into GAC
10. Move next step and right click solution of same project and add new class library of C# as name "BizTalkLive.ContextPropertyAccessor" that do to call property promoted value in biztalk orchestration expression shape. See the following code then build this project and finally installed dll in gac.
using Microsoft.XLANGs.BaseTypes;
using Microsoft.XLANGs.Core;
using System;
using System.Collections;
namespace BizTalkLive.ContextPropertyAccessor
{
public class ContextAccessor
{
public static Hashtable GetContext(XLANGMessage message)
{
try
{
foreach (Segment segment in Service.RootService._segments)
{
IDictionary fields =
Context.FindFields(
typeof(XLANGMessage)
,
segment.ExceptionContext);
foreach (DictionaryEntry field in fields)
{
XMessage msg = (field.Value as XMessage);
if (msg == null)
continue;
if (String.Compare(msg.Name, message.Name) != 0)
continue;
return msg.GetContextProperties();
}
}
}
catch (Exception ex)
{
// do not
provoke failure
throw ex;
}
return new Hashtable();
}
public static string GetContextProperty(XLANGMessage message, string PropertyName, string PropertyNamespace)
{
string Property = "False";
try
{
Microsoft.XLANGs.BaseTypes.XmlQName qname = new XmlQName(PropertyName, PropertyNamespace);
foreach (Segment segment in Service.RootService._segments)
{
IDictionary fields =
Context.FindFields(
typeof(XLANGMessage)
,
segment.ExceptionContext);
foreach (DictionaryEntry field in fields)
{
XMessage msg = (field.Value as XMessage);
if (msg == null)
continue;
if (String.Compare(msg.Name, message.Name) != 0)
continue;
if
(msg.GetContextProperties().ContainsKey(qname))
{
// get
the property from GetContextProperties
Property =
msg.GetContextProperties()[qname].ToString();
}
else if (msg.GetContentProperties().ContainsKey(qname))
{
// get the property from GetContentProperties
Property =
msg.GetContentProperties()[qname].ToString();
}
return Property;
}
}
}
catch (Exception ex)
{
throw ex;
// do not
provoke failure
//
probably best to add some logging here
}
return Property;
}
}
}
11. Now reference both dll i.e. BizTalkLive.UnZip and BizTalkLive.ContextPropertyAccessor in biztalk project "BizTalkLive.Unzip.Disassemble", see the following image-
12. Add new receive pipeline name as "Rcv_UnZipDisassemble" now Click on toolbox of receive pipeline and then right click and click choose items.. and select BizTalk Pipeline Component tag and click Browse.. button from right side of bottom and select BizTalkLive.UnZip.dll from the already installed gac assembly. Now a new toolbox added in pipeline toolbox name as unzip_Disassembler then select it and place on disassemble stage and also after add XML disassembler.
13. Now add two schema one property schema and one schema for
xml file that unzip from zip file, Please see the following picture and also you can download complete source in the last of this post so that you can easily create both schemas.
14. Now see the following below picture its show how I will design orchestration flow, firstly message come from receive location using custom unzip receive pipeline then I am using a expression shape where i get filestatus value by using xlangs context message promote schema property. In the last configure port, configure logical file port to send xml file in local directory.
15. In the last part of biztalk project unzip custom pipeline disassembler, right click on solution and set same name of biztalk project as it solution name and again right click on solution and deployed it. Now create receive port then create receive location and select receive pipeline set two disassemble component i.e. one is property schema's target namespace and for 2nd one message type of xml schema that use in xml files are zipped. see the following image-
16. Now create two send port one for route same zip file to local directory by using filter condition that I have promoted in UnZip disassemble method i.e. file extension a d receive port and second send port use to copy all xml files in local folder. Please see the following picture-
To download Ionic dll please click this link - Downlaod Ionic Dll
To download complete project source code please click this link - Download Source Code
!! Keep Visiting BizTalkLive !!
very nice article automation
ReplyDeleteThis is an amazing blog, and it helps students.Thanks for haring
ReplyDeleteBiztalk
Online course Bangalore