65.9K
CodeProject 正在变化。 阅读更多。
Home

在自定义管道组件中解压缩文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (3投票s)

2011年2月1日

CPOL

5分钟阅读

viewsIcon

47170

downloadIcon

1148

如何在自定义接收管道组件中解压缩文件

引言

在本文中,我将介绍如何在 BizTalk 接收管道的拆装阶段开发自定义管道组件来解压缩文件。

此组件有一个属性,允许用户输入用于解压缩文件的密码。收到的存档中的所有文件都将被解压缩。

创建自定义管道组件的许多代码都是基础性的,可以使用向导轻松实现。核心代码位于 IDisassemblerComponent 区域,这是本文的最后一部分代码。

代码

此项目在 Visual Studio 中创建为新的类库,并使用强名称密钥文件进行签名。

添加了两个引用:Microsoft.BizTalk.Pipeline.dllIonic.Zip.dll

此项目中的类重命名为 UnzipDisassembler ,代码以添加以下命名空间开始。

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Ionic.Zip;
using System.IO;

在下面的代码中,我为类添加了两个属性。第一个表示这是一个管道组件,第二个属性将组件限制为只能在管道的拆装阶段使用。

管道组件实现的具体接口决定了该管道组件与其他组件的区别。一旦组件实现了接口,它就可以被 BizTalk 运行时调用。所有组件和组件类别都位于 Microsoft.BizTalk.Component.Interop 命名空间中。拆装器管道组件需要实现 IBaseComponentIComponentUI IDisassemblerComponent 接口。此外,下面的类还实现了 IPersistPropertyBag 接口,但这并非必需。

namespace Stm.UnzipDisassembler
{
   [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
   [ComponentCategory(CategoryTypes.CATID_DisassemblingParser)]
   [System.Runtime.InteropServices.Guid("90E45487-0AFC-49F5-81EB-737635678A17")]
   public class UnzipDisassembler : 
	IBaseComponent, IComponentUI, IDisassemblerComponent, IPersistPropertyBag
   {

在类内部,我实现了所有接口所需的属性和方法。

我从 IBaseComponent 接口开始。该接口提供了有关组件的基本信息的属性。

#region IBaseComponent
private const string _description = "Pipeline component used to unzip messages";
private const string _name = "UnzipDisassembler";
private const string _version = "1.0.0.0";

public string Description
{
   get { return _description; }
}
public string Name
{
   get { return _name; }
}
public string Version
{
   get { return _version; }
}
#endregion

IComponentUI 接口定义了在管道设计器环境中使用的方法和属性。为保持简单,我在此处未提供任何代码。

#region IComponentUI
private IntPtr _icon = new IntPtr();
public IntPtr Icon
{
   get { return _icon; }
}
public System.Collections.IEnumerator Validate(object projectSystem)
{
   return null;
}
#endregion

接下来,我实现了 IPersistPropertyBag 接口。这是为了存储管道组件的属性信息。在接收管道中使用时,此组件允许用户在 BizTalk 管理控制台的接收管道配置的属性字段中输入密码。如果解压缩存档需要密码,则会使用此属性。

#region IPersistPropertyBag
private string _password;

public string Password
{
   get { return _password; }
   set { _password = value; }
}
public void GetClassID(out Guid classID)
{
   classID = new Guid("625BBF88-0F86-419A-83AE-B15A976A6715");
}
public void InitNew()
{
}
public void Load(IPropertyBag propertyBag, int errorLog)
{
   object val1 = null;
   try
   {
      propertyBag.Read("Password", out val1, 0);
   }
   catch (ArgumentException)
   {
   }
   catch (Exception ex)
   {
      throw new ApplicationException("Error reading PropertyBag: " + ex.Message);
   }
      if (val1 != null)
         _password = (string)val1;
}
public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
   object val1 = (object)_password;
   propertyBag.Write("Password", ref val1);
}
#endregion

当解压缩存档需要密码时,将使用 Password 属性。

Load 方法将 PropertyBag 中的值读取到属性中。我在管道设计器中将组件添加到拆装阶段时遇到了一个错误消息。尽管组件运行正常,但为了避免此错误消息,我添加了一个 catch 块来 catch ArgumentException

Save 方法将属性中的值写入 PropertyBag

GetClassID 返回组件的唯一标识值。

InitNew 用于初始化要持久化的对象到组件属性中。此项目不需要。

核心接口是 IDisassemblerComponent。拆装器的目的是允许管道检查传入的文档并将其分解为更小的文档。

IDisassemblerComponent 有两个方法:Disassemble GetNextBizTalk 运行时首先调用 Disassemble 方法,并将原始消息和管道上下文传递给它。然后,它调用 GetNext 方法,该方法返回类型为 IBaseMessage 的新消息,直到组件确定所有消息都已创建,然后返回 null

此组件在 Disassemble 方法中创建所有消息,并将它们放入队列结构中。每次调用 GetNext 方法时,它都会从队列中移除并返回一条消息。

#region IDisassemblerComponent
private System.Collections.Queue _qOutMessages = new System.Collections.Queue();
public void Disassemble(IPipelineContext pContext,IBaseMessage pInMsg)
{
   IBaseMessagePart bodyPart = pInMsg.BodyPart;

   if(bodyPart != null)
   {
      Stream originalStream = bodyPart.GetOriginalDataStream();

      if(originalStream != null)
      {
         using (ZipInputStream zipInputStream = new ZipInputStream(originalStream))
         {
            if (_password != null)
               if (_password.Length > 0)
                  zipInputStream.Password = _password;

            ZipEntry entry = zipInputStream.GetNextEntry();                        
                        
            while (entry != null)
            {
               MemoryStream memStream = new MemoryStream();
               byte[] buffer = new Byte[1024];

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

               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);
               _qOutMessages.Enqueue(outMessage);

                entry = zipInputStream.GetNextEntry();
            }                       
         }
      }
   }            
}
public IBaseMessage GetNext(IPipelineContext pContext)
{
   if (_qOutMessages.Count > 0)
      return (IBaseMessage)_qOutMessages.Dequeue();
   else
      return null;
}
#endregion
}// Ends the class
}// Ends the namespace

上面的代码首先声明了一个用于消息的 private 队列。Disassmeble 方法检查输入流是否包含数据,然后从原始输入流创建一个 ZipInputStream 。可以为 ZipInputStream 设置密码。

while 循环中的代码(只要条目不为 null 就运行)将针对 ZipInputStream 中的每个条目运行。创建一个 MemoryStream,称为 memStream,然后从 zipInputStream 读取数据并写入 MemoryStream

memStream 完成后,将基于当前管道和传入消息的上下文创建一个消息 outMessage。此消息的 BodyPart 的数据设置为 memStream。该消息现在包含从传入的 zip 消息中提取的一个条目。该消息被放入队列。

zip 消息中的每个条目现在都是队列中的一条新消息。GetNext 方法在每次被调用时都会从队列中移除并返回这些消息。

安装和测试组件

要使用此组件,需要构建该项目,并在 BTS 接收管道项目中,必须将该组件 DLL 添加到工具箱中,并在拆装阶段使用它。Password 属性的值可以在管道设计时设置。部署管道后,也可以在 BTS 管理控制台的接收管道配置中设置此属性。

提示:如果在管道中使用组件后需要对其进行更改和重新构建,则在构建组件时可能会出现问题,因为 DLL 文件可能被另一个进程占用。要解决此问题,我使用 WhoLockedMe 应用程序来查看哪些进程锁定了文件,然后可以终止这些进程。WhoLockedMe 是免费的,很容易在互联网上搜索并下载。

另请参阅 在自定义管道组件中压缩文件

历史

  • 2011 年 2 月 1 日:初始发布
© . All rights reserved.