BizTalk - 无法提升属性

时间:2016-01-02 17:32:51

标签: biztalk pipeline biztalk-2013r2

使用BizTalk 2013r2 CU1,我为我的入站xsd创建了一个属性架构并部署了该应用程序。

当我使用标准的“xml receive”管道收到样本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可能存在问题 - 还有其他人遇到过这个问题吗?

2 个答案:

答案 0 :(得分:7)

当XML Disassembler在您的自定义管道中执行时,无法保证您的属性已被提升。

传入消息作为流到达管道,数据指针设置在流的开头 我认为XML反汇编程序不会读取流,它会将其包装到某个流包装器类中,该类将在实际读取流时填充提升的属性。
必须至少读取一次流:当消息插入消息框时。因此可以保证属性会得到提升,但是您无法假设它将在&#34; Validate&#34;之前完成。阶段执行。

要确保这确实是您遇到的问题:在将消息导入消息框后检查您的消息。
如果您的推广财产在那里,我所描述的可能是正在发生的事情。

<强>解决方案:

要使自定义管道组件正常工作,最好的解决方案就是像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)
{
}

解决问题的一种效率较低的方法是在&#34; Validate&#34;中自定义组件中完全读取流。 stage并将流指针放回流的开头。

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 parameter to EventHandler

答案 1 :(得分:2)

您可以在业务流程中为验证阶段做任何计划吗?那会容易得多。

如果没有,这个特定问题的最常见解决方案是一个中间管道组件,它强制对流进行完全读取,但从技术上讲,您只需要读取直到被提升节点被击中。