This article intends to demonstrate the step-by-step procedures required to process a zipped file which has files of multiple types.
A compressed message (zipped) is received and it has files of a various type which is to be processed individually and is to be routed to destination folder for further processing.
There is no dedicated default pipeline for accepting the zipped message and unzipping it. Therefore, there arises a need of developing a custom pipeline which will accept the zipped message and a custom disassembler component which will decompress the message and will produce individual files. But only unzipping the message is not sufficient as to route individual files based on its type, some property promotion also needs to be done.
Steps involved in implementing the solution:
The sample input message (DemoZipSampleInput.zip) used here has xml(.xml),txt(.txt) and image files(.tiff,.jpg) which are zipped.
1. Create a C# class library project which will hold the custom disassembler component, the purpose of this component is to split messages and promote a custom context property.
2. To develop custom Disassembler Component, four interfaces are to be implemented - IBaseComponent, IComponentUI, IPersistPropertyBag and IDisassemblerComponent. And these Interfaces have Methods and Properties defined which should be implemented. 3. In order to implement these 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. 4. Right click the project and add a reference to Microsoft.BizTalk.Pipeline.dll and Iconic.zip.
using
System;
System.Collections.Generic;
System.Linq;
System.Text;
System.IO;
Microsoft.BizTalk.Message.Interop;
Microsoft.BizTalk.Component.Interop;
Ionic.Zip;
//Attributes of class
[System.Runtime.InteropServices.Guid(
"9ABA4232-1F8E-4a45-B12D-9BE50160464B"
)]
5. It’s the Disassemble method of IDisaasemblerComponent Interface where the logic to unzip message and promote a custom property will be done.
private
System.Collections.Queue OutFiles =
new
System.Collections.Queue();
public
void
Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
{
IBaseMessagePart msgBodyPart = pInMsg.BodyPart;
if
(msgBodyPart !=
null
)
Stream msgBodyPartStream = msgBodyPart.GetOriginalDataStream();
(msgBodyPartStream !=
(ZipInputStream zipInputStream =
ZipInputStream(msgBodyPartStream))
ZipEntry entry = zipInputStream.GetNextEntry();
while
(entry !=
MemoryStream memStream =
MemoryStream();
byte
[] buffer =
Byte[1024];
int
bytesRead = 1024;
(bytesRead != 0)
bytesRead = zipInputStream.Read(buffer, 0, buffer.Length);
memStream.Write(buffer, 0, bytesRead);
}
//Creating outMessage
IBaseMessage outMessage;
outMessage = pContext.GetMessageFactory().CreateMessage();
outMessage.AddPart(
"Body"
, pContext.GetMessageFactory().CreateMessagePart(),
true
);
memStream.Position = 0;
outMessage.BodyPart.Data = memStream;
outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
//Add outMessage to queue
OutFiles.Enqueue(outMessage);
entry = zipInputStream.GetNextEntry();
//Creating custom context property to hold extension of file
string
extension =
.Empty;
extension = entry.FileName.Substring(entry.FileName.IndexOf(
"."
));
//Promoting the custom property
pInMsg.Context.Promote(
"Extension"
,
"https://DemoZip.ZipMessageProperties"
, extension);
namespace
UnzipMessages
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
//Generate unique identifier
class
UnzipMessageDisassembler:IBaseComponent,
ComponentUI,
IDisassemblerComponent,
IPersistPropertyBag
//Implementing Interfaces
#region IBaseComponent
const
description =
"UnzipMessages pipeline component"
;
name =
"UnzipMessageDisaasembler"
version =
"1.0.0.0"
Description
get
return
description
Name
name;
Version
version;
#endregion
#region IComponentUI
IntPtr icon =
IntPtr();
IntPtr Icon
icon;
System.Collections.IEnumerator Validate(
object
projectsystem)
#region IPersistPropertyBag
GetClassID(
out
Guid classid)
classid =
System.Guid(
InitNew()
Load(IPropertyBag propertyBag,
errorlog)
Save(IPropertyBag propertyBag,
bool
clearDirty,
saveAllProperties)
#region IDisassemblerComponent
// This component will read the zipped input message as a stream and with the help
// of Zip library the message will unzipped and stored in the Queue.
IBaseMessage GetNext(IPipelineContext pContext)
(OutFiles.Count > 0)
(IBaseMessage)OutFiles.Dequeue();
else
1. Right-click the project, Add new item and select ReceivePipeline template.
2. To use the above-developed component it needs to be made available in the tool box and to do so copy the component dll at location : C:\Program Files\Microsoft BizTalk Server 2010\Pipeline Components
3. Next to reset the tool box (right click ToolBox section and select Reset ToolBox), doing this makes this component available in the Pipeline Designer Tool Box.
4. Drag and Drop the Component in Disassemble stage.
DemoZip.Extension == .jpg DemoZip.Extension == .jpeg BTS.ReceivePortName == RecZipFile
2.3.1 Configuring Send Port for Text files
FileName: %MessageID% .txt Send pipeline: PassThruTransmit
2.4.1 Configuring Send Port for Tiff files
FileName: %MessageID% .tiff Send pipeline: PassThruTransmit