You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BizTalk Server 2016接收Zip文件解压失败问题排查及方案咨询

BizTalk Server 2016 接收管道解压问题排查与替代方案

一、现有自定义解压组件问题排查

1. 代码逻辑核心问题

  • 上下文属性操作错误:循环中修改**原输入消息(pInMsg)**的上下文并克隆给输出消息,会导致所有输出消息的上下文被覆盖;且应直接在新创建的outMessage上下文上推广属性,而非原消息。
  • 流处理不规范:
    • 未重置原消息流msgBodyPartStream的位置,可能导致ZipInputStream读取不全;
    • 直接将MemoryStream赋值给outMessage.BodyPart.Data,未使用BizTalk的ReadOnlySeekableStream包装,可能导致流被重复读取或损坏。
  • 文件名处理漏洞:当压缩包内文件无扩展名时,entry.FileName.IndexOf(".")返回-1,Substring会抛出异常,中断解压流程,可能直接返回原Zip流。
  • 第三方库潜在问题:Ionic.Zip(DotNetZip)旧版本存在ZipInputStream读取bug,建议升级至最新稳定版。

2. 配置与注册问题

  • 确认组件已正确注册至GAC,且接收管道的Disassemble阶段已添加该组件,无其他冲突的Disassembler组件。
  • 检查接收管道是否被正确关联到接收位置。

修复后的核心代码片段

public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
{
    IBaseMessagePart msgBodyPart = pInMsg.BodyPart;
    if (msgBodyPart != null)
    {
        Stream msgBodyPartStream = msgBodyPart.GetOriginalDataStream();
        if (msgBodyPartStream != null)
        {
            // 重置原流位置,确保从开头读取
            msgBodyPartStream.Position = 0;
            using (ZipInputStream zipInputStream = new ZipInputStream(msgBodyPartStream))
            {
                ZipEntry entry = zipInputStream.GetNextEntry();
                while (entry != null)
                {
                    MemoryStream memStream = new MemoryStream();
                    byte[] buffer = new Byte[4096]; // 增大缓冲区提升效率
                    int bytesRead;
                    while ((bytesRead = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        memStream.Write(buffer, 0, bytesRead);
                    }

                    // 创建输出消息
                    IBaseMessage outMessage = pContext.GetMessageFactory().CreateMessage();
                    IBaseMessagePart outBodyPart = pContext.GetMessageFactory().CreateMessagePart();
                    outMessage.AddPart("Body", outBodyPart, true);

                    // 使用BizTalk包装类处理流,确保可重入
                    memStream.Position = 0;
                    outBodyPart.Data = new ReadOnlySeekableStream(memStream);

                    // 安全处理扩展名
                    string extension = string.Empty;
                    int dotIndex = entry.FileName.LastIndexOf(".");
                    if (dotIndex != -1 && dotIndex < entry.FileName.Length -1)
                    {
                        extension = entry.FileName.Substring(dotIndex);
                    }

                    // 在输出消息上下文上推广属性
                    outMessage.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
                    outMessage.Context.Promote("Extension", "https://DemoZip.ZipMessageProperties", extension);

                    OutFiles.Enqueue(outMessage);
                    entry = zipInputStream.GetNextEntry();
                }
            }
        }
    }
}

二、BizTalk接收管道解压的其他方法

1. 使用.NET原生ZipArchive(无第三方依赖)

改用System.IO.Compression.ZipArchive(.NET 4.6+支持,BizTalk 2016兼容)实现解压,避免第三方库依赖:

public void Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
{
    IBaseMessagePart msgBodyPart = pInMsg.BodyPart;
    if (msgBodyPart != null)
    {
        Stream msgBodyPartStream = msgBodyPart.GetOriginalDataStream();
        msgBodyPartStream.Position = 0;
        using (ZipArchive archive = new ZipArchive(msgBodyPartStream, ZipArchiveMode.Read))
        {
            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                if (string.IsNullOrEmpty(entry.Name)) continue; // 跳过目录
                MemoryStream memStream = new MemoryStream();
                using (Stream entryStream = entry.Open())
                {
                    entryStream.CopyTo(memStream);
                }
                memStream.Position = 0;
                // 创建输出消息逻辑同修复后的代码
                // ...
            }
        }
    }
}

2. 接收位置预处理脚本(PowerShell)

在接收位置的预处理脚本中调用PowerShell解压文件,再由BizTalk处理解压后的内容:

$zipPath = $Env:BT_INPUT_FILE
$extractPath = [System.IO.Path]::GetDirectoryName($zipPath)
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipPath, $extractPath)
# 删除原Zip文件
Remove-Item $zipPath -Force

注意:需确保BizTalk宿主账户有足够权限读取、写入目标目录。

3. 使用社区BizTalk组件

利用BizTalk社区维护的开源组件(如BizTalk Factory的Zip组件),无需自行开发,直接在管道中配置使用。


内容的提问来源于stack exchange,提问作者Harsh Shelar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:40:21