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

BizTalk自定义发送管道仅解压单个消息而非全部的问题

问题根源

你的代码逻辑存在错误:循环处理Zip内每个文件时,反复将原消息pInMsg的Body数据替换为当前解压后的内容,最后仅返回这一条被多次覆盖的原消息,自然只会输出最后一个解压文件的内容。

BizTalk发送管道的预组装阶段要生成多条消息,必须通过消息队列+多次调用Execute方法的机制实现——管道框架会反复调用Execute,直到返回null才停止处理。

修复后的代码
[Guid("885186F0-8846-4AD1-BC3F-D0066844B871")]
[ComponentCategory(CategoryTypes.CATID_Any)]
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
public class UnzipperComponent : IBaseComponent, IComponent, IComponentUI, IPersistPropertyBag
{
    private readonly Queue<IBaseMessage> _inboundMsgQueue = new Queue<IBaseMessage>();

    IBaseMessage IComponent.Execute(IPipelineContext pContext, IBaseMessage pInMsg)
    {
        // 第一次调用时处理输入消息,生成所有解压消息到队列
        if (pInMsg != null && _inboundMsgQueue.Count == 0)
        {
            using (var currentPartSource = pInMsg.BodyPart.GetOriginalDataStream())
            {
                if (pInMsg.BodyPart != null && currentPartSource != null)
                {
                    using (var seekableStream = new MemoryStream())
                    {
                        currentPartSource.CopyTo(seekableStream);
                        seekableStream.Seek(0, SeekOrigin.Begin);

                        using (var unzipArchive = new ZipArchive(seekableStream, ZipArchiveMode.Read, true))
                        {
                            foreach (var entry in unzipArchive.Entries)
                            {
                                // 跳过Zip里的目录条目
                                if (string.IsNullOrEmpty(entry.Name)) continue;

                                using (var entryStream = entry.Open())
                                using (var outStream = new MemoryStream())
                                {
                                    entryStream.CopyTo(outStream);
                                    outStream.Seek(0, SeekOrigin.Begin);

                                    // 创建新消息实例
                                    var newMsg = pContext.GetMessageFactory().CreateMessage();
                                    newMsg.Context = PipelineUtil.CloneMessageContext(pInMsg.Context);
                                    var bodyPart = pContext.GetMessageFactory().CreateMessagePart();
                                    bodyPart.Data = outStream;
                                    bodyPart.Charset = "UTF-8";
                                    // 根据文件类型设置ContentType,可按需扩展判断逻辑
                                    bodyPart.ContentType = entry.Name.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) 
                                        ? "application/pdf" 
                                        : entry.Name.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)
                                            ? "application/xml"
                                            : "text/plain";
                                    
                                    // 用当前UTC时间生成唯一文件名后缀
                                    var timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
                                    newMsg.Context.Promote(
                                        "ReceivedFileName", 
                                        "http://schemas.microsoft.com/BizTalk/2003/file-properties", 
                                        $"{entry.Name}_{timestamp}");

                                    newMsg.AddPart("Body", bodyPart, true);
                                    // 注册资源到上下文,避免BizTalk回收时泄漏
                                    pContext.ResourceTracker.AddResource(outStream);
                                    _inboundMsgQueue.Enqueue(newMsg);
                                }
                            }
                        }
                    }
                }
            }
        }

        // 每次调用返回队列中的一条消息,队列为空时返回null结束处理
        return _inboundMsgQueue.Count > 0 ? _inboundMsgQueue.Dequeue() : null;
    }

    // 其他接口(IComponentUI、IPersistPropertyBag等)的实现代码保持原有逻辑即可,此处省略
}
关键修改点
  • 用队列存储所有生成的解压消息,而非覆盖原消息
  • 首次调用Execute时处理输入Zip文件,将所有解压后的消息加入队列
  • 后续Execute调用从队列中取消息返回,直到队列为空返回null
  • 修复细节问题:
    • 跳过Zip中的目录条目,避免生成空消息
    • 用using包裹entry.Open()返回的流,确保资源释放
    • 替换无效的DateTime初始化,用当前UTC时间生成唯一文件名后缀
    • 根据文件类型动态设置ContentType
    • 注册MemoryStream到ResourceTracker,防止资源泄漏

内容的提问来源于stack exchange,提问作者Hans Peter Eriksson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:13:11