使用BizTalk 2013r2 CU1,我为我的入站xsd创建了一个属性模式并部署了该应用程序.
当我使用标准的"xml接收"管道收到样本xml文档时,我可以看到所需的元素按预期被提升到上下文中.
然后,我创建了一个自定义管道,其中包含"Disassemble"阶段中的"XML反汇编程序"组件和"验证"阶段中的自定义组件.此自定义组件需要从上下文中读取提升的属性.但是,我发现当我将接收位置从"xml接收"管道切换到我的自定义管道时,我的属性不会被提升.我在自定义组件中使用以下代码来写出消息上下文中的项列表:
for (int x = 0; x < contextList.CountProperties; x++) { contextList.ReadAt(x, out name, out nspace); string value = contextList.Read(name, nspace).ToString(); contextItems += "Name: " + name + " - " + "Namespace: " + nspace + " - " + value + "\r\n"; if (name == _ContextPropertyName && nspace == _ContextPropertyNamespace) promotedPropFound = true; } Helpers.EventLogHelper eventHelper = new EventLogHelper(); eventHelper.LogEvent(string.Format("Context items:{0}", contextItems)); if (promotedPropFound == false) throw new Exception(string.Format("Unable to find promoted property with name[{0}] and namespace [{1}]", _ContextPropertyName, _ContextPropertyNamespace));
从事件日志中的输出我可以看到某些属性,如MessageType已被提升,但我的自定义属性没有.同样,如果我更改接收位置以使用标准的"xml接收"管道,那么该属性将从同一个xml文档的副本中提升(我通过停止订阅发送端口并从管理控制台查看上下文来检查此属性).
我发现这很奇怪,因为相同的"XML反汇编程序"组件存在于两个管道的相同"反汇编"阶段,具有相同(默认)配置.我开始认为2013r2CU1可能有问题 - 还有其他人遇到过同样的问题吗?
当XML Disassembler在您的自定义管道中执行时,无法保证您的属性已被提升.
传入消息作为流到达管道,数据指针设置在流的开头.
我认为XML反汇编程序不会读取流,它将它包装到某个流包装器类中,该类将在实际读取流时填充提升的属性.
必须至少读取一次流:当消息插入消息框时.因此可以保证属性将得到提升,但您不能假设它将在"Validate"阶段执行之前完成.
要确保这确实是您遇到的问题:在将消息导入消息框后检查您的消息.
如果您的推广财产在那里,我所描述的可能是正在发生的事情.
解决方案:
要使自定义管道组件正常工作,最好的解决方案就是像XML反汇编程序一样:获取传入流并将其包装到流包装器类中,该类可以触发您需要的任何功能.
程序集Microsoft.BizTalk.Streaming.dll有一些你可能感兴趣的包装类:ForwardOnlyEventingReadStream.
这个类有一个事件AfterLastReadEvent.您可以创建一些EventHandler并让它订阅此事件,以便仅在完全读取流后触发您的自定义功能,并且所有属性都已提升.
您的自定义组件将如下所示:
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message) { Stream stream = message.BodyPart.GetOriginalDataStream(); CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream); eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler(DoSomething); message.BodyPart.Data = eventingReadStream; return message; } private static void DoSomething(object src, EventArgs args) { }
解决问题的一种效率较低的方法是在"验证"阶段在自定义组件中完全读取流,并将流指针放回流的开头.
当您在管道组件中操作消息流时,Microsoft有一些指导原则:https: //msdn.microsoft.com/en-us/library/aa577699.aspx
更新:
OP需要将消息上下文传递给事件处理程序.可以使用Lambda表达式:
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message) { Stream stream = message.BodyPart.GetOriginalDataStream(); CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream); eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler((src, args) => DoSomething(src, args, message.Context)); message.BodyPart.Data = eventingReadStream; return message; } private static void DoSomething(object src, EventArgs args, IBaseMessageContext messageContext) { }
这个SO问题可以引用附加参数的参考: Pass参数传递给EventHandler