A common problem that most
BizTalk projects encounter is having to either send or receive
compressed data in the formof a ZIP file. Often, the incoming ZIP file
has multiple entries, each of which need to be submitted to BizTalk. In
most cases, these files are XML files, but in some situations, they can
be either flat files or binary files instead. The examples in the
following sections outline a potential simplified solution for sending
and receiving zipped information. Additionally, you'll get a chance to
explore ways to augment the solution using new functionality within
BizTalk.
Sending Simple Zipped Files
In order to send a ZIP file
from BizTalk, you will need to create a custom send pipeline and a
custom encoding pipeline component. The pipeline component will be
responsible for examining the incoming message, getting access to the
message's data, compressing it, and returning it to BizTalk. The
simplest scenario is the "single message in/single message out"
scenario. Here, a message is sent to the send pipeline, it is
compressed, and a single message is sent out. The pipeline component
required for this is documented in the following class:
Imports Microsoft.VisualBasic
Imports System
Imports System.ComponentModel
Imports System.Collections
Imports System.Diagnostics
Imports System.Drawing
Imports System.IO
Imports System.Reflection
Imports Microsoft.BizTalk.Component.Interop
Imports Microsoft.Utility.PipelinePropertyAttribute
Imports ICSharpCode.SharpZipLib.Zip
Namespace ABC.BizTalk.PipelineComponents
<ComponentCategory(CategoryTypes.CATID_PipelineComponent),_
ComponentCategory(CategoryTypes.CATID_Encoder),_
System.Runtime.InteropServices.Guid("56C7B68B-F288-4f78-A67F-20043CA4943E")> _
Public Class ZipEncodingComponent
Implements IBaseComponent, Microsoft.BizTalk.Component.Interop.IComponent,_
Microsoft.BizTalk.Component.Interop.IPersistPropertyBag, IComponentUI
Private resourceManager As System.Resources.ResourceManager = New_
System.Resources.ResourceManager("ABC.BizTalk.PipelineComponents",_
System.Reflection.Assembly.GetExecutingAssembly())
Private _compressionlevel As String
Private _filename As String
Private _password As String
Private Const DEFAULT_COMPRESSIONLEVEL_TEXT As String = "5"
Private Const DEFAULT_COMPRESSIONLEVEL As Integer = 5
Private Const DEFAULT_FILENAME As String = "ABCBizTalkSendFile"
#Region "IBaseComponent"
<Browsable(False)> _
Public ReadOnly Property Name() As String
Get
Return "ZIP encoding component"
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property Version() As String
Get
Return "1.0"
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property Description() As String
Get
Return "Pipeline Component which will encode an outgoing_
message as a ZIP file."
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property Icon() As System.IntPtr
Get
Return (CType(resourceManager.GetObject("IconBitmap"),_
Bitmap)).GetHicon()
End Get
End Property
#End Region
Public Property Password() As String
Get
Return _password
End Get
Set(ByVal value As String)
_password = value
End Set
End Property
Public Property Filename() As String
Get
Return _filename
End Get
Set(ByVal value As String)
_filename = value
End Set
End Property
Public Property CompressionLevel() As String
Get
Return _compressionlevel
End Get
Set(ByVal value As String)
_compressionlevel = value
End Set
End Property
Private Function Encode(ByVal inStream As Stream) As Stream
Dim outStream As Stream = inStream
Dim inFile As String = Path.GetTempFileName()
Dim outFile As String = Path.ChangeExtension(inFile, "zip")
Try
Dim zipStream As ZipOutputStream = New_
ZipOutputStream(File.Create(outFile))
' get password, if supplied
If _password.IsNullOrEmpty Then
zipStream.Password = _password
End If
' get compression level, if supplied
Dim compressionlevel As Integer = DEFAULT_COMPRESSIONLEVEL
If (Not _compressionlevel Is Nothing) AndAlso (_compressionlevel <>_
"") Then
compressionlevel = Convert.ToInt32(_compressionlevel)
End If
If (compressionlevel < 0) OrElse (compressionlevel > 9) Then
compressionlevel = DEFAULT_COMPRESSIONLEVEL
End If
zipStream.SetLevel(compressionlevel)
' get message filename, if supplied
Dim filename As String
If ((Not _filename Is Nothing) AndAlso (_filename <> "")) Then
filename = (_filename)
Else
filename = (DEFAULT_FILENAME)
End If
Dim entry As ZipEntry = New ZipEntry(filename)
zipStream.PutNextEntry(entry)
' copy the input into the compressed output stream
Dim buffer As Byte() = New Byte(4095) {}
Dim count As Integer = inStream.Read(buffer, 0, buffer.Length 0)
Do While (count <> 0)
zipStream.Write(buffer, 0, count)
count = inStream.Read(buffer, 0, buffer.Length 0)
Loop
zipStream.Finish()
zipStream.Close()
outStream = ReadFileToMemoryStream(outFile)
Catch ex As Exception
System.Diagnostics.Debug.WriteLine(ex)
Finally
If File.Exists(inFile) Then
File.Delete(inFile)
End If
If File.Exists(outFile) Then
File.Delete(outFile)
End If
End Try
Return outStream
End Function
#Region "IPersistPropertyBag Members"
Public Sub InitNew()
End Sub
Public Sub GetClassID(<System.Runtime.InteropServices.Out()> ByRef_
classID As Guid)
classID = New Guid("0F94CF83-0B04-49a6-B73C-70473E0CF96F")
End Sub
Public Sub Load(ByVal propertyBag As IPropertyBag, ByVal errorLog_
As Integer)
Dim value As String
value = Convert.ToString((ReadPropertyBag(propertyBag, "Password")))
If Not value Is Nothing Then
_password = value
End If
value = Convert.ToString((ReadPropertyBag(propertyBag, "Filename")))
If Not value Is Nothing Then
_filename = value
End If
value = Convert.ToString(ReadPropertyBag(propertyBag,_
"CompressionLevel"))
If Not value Is Nothing Then
_compressionlevel = value
End If
End Sub
Public Sub Save(ByVal propertyBag As IPropertyBag, ByVal clearDirty As_
Boolean, ByVal saveAllProperties As Boolean)
Dim value As String
value = Convert.ToString(_password)
WritePropertyBag(propertyBag, "Password", value)
value = Convert.ToString(_filename)
WritePropertyBag(propertyBag, "Filename", value)
value = Convert.ToString(_compressionlevel)
WritePropertyBag(propertyBag, "CompressionLevel", value)
End Sub
#End Region
#Region "IComponent Members"
Public Function Execute(ByVal pContext As IPipelineContext, ByVal pInMsg As_
Microsoft.BizTalk.Message.Interop.IBaseMessage) As_
Microsoft.BizTalk.Message.Interop.IBaseMessage
If Not pInMsg Is Nothing Then
Dim originalStream As Stream = _
pInMsg.BodyPart.GetOriginalDataStream()
pInMsg.BodyPart.Data = Encode(originalStream)
pContext.ResourceTracker.AddResource(pInMsg.BodyPart.Data)
End If
Return pInMsg
End Function
#End Region
#Region "IComponentUI Members"
' <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 Function Validate(ByVal projectSystem As Object) As IEnumerator
' example implementation:
' ArrayList errorList = new ArrayList();
' errorList.Add("This is a compiler error");
' return errorList.GetEnumerator();
Return Nothing
End Function
Public Shared Function ReadFileToMemoryStream(ByVal fromFilename _
As String) As MemoryStream
Dim file As FileStream = Nothing
Try
file = New FileStream(fromFilename, System.IO.FileMode.Open)
Dim memStream As MemoryStream = New MemoryStream()
Dim tmpBuff As Byte() = New Byte(4095) {}
Dim bytesRead As Integer = 0
bytesRead = file.Read(tmpBuff, 0, tmpBuff.Length)
memStream.Write(tmpBuff, 0, bytesRead)
Do While bytesRead <> 0
bytesRead = file.Read(tmpBuff, 0, tmpBuff.Length)
memStream.Write(tmpBuff, 0, bytesRead)
Loop
file.Close()
file = Nothing
memStream.Position = 0
Return memStream
Finally
If Not file Is Nothing Then
file.Close()
End If
End Try
End Function
#End Region
#Region "Private Helpers"
Public Shared Function ReadPropertyBag(ByVal pb As_
Microsoft.BizTalk.Component.Interop.IPropertyBag, ByVal propName As_
String) As Object
Dim value As Object
value = Nothing
Try
pb.Read(propName, value, 0)
Catch argException As ArgumentException
Return value
Catch ex As Exception
Throw New ApplicationException(ex.Message)
End Try
Return value
End Function
''' <summary>
''' Writes property values into a property bag.
''' </summary> ''' <param name="pb">Property bag.</param>
''' <param name="propName">Name of property.</param>
''' <param name="val">Value of property.</param>
Public Shared Sub WritePropertyBag(ByVal pb As _
Microsoft.BizTalk.Component.Interop.IPropertyBag, ByVal propName As _
String, ByVal val As Object)
Try
pb.Write(propName, val)
Catch ex As Exception
Throw New ApplicationException(ex.Message)
End Try
End Sub
#End Region
End Class
End Namespace