2016-01-02 26 views
1

使用BizTalk 2013r2 CU1,我为入站xsd创建了属性架构并部署了应用程序。BizTalk - 无法提升属性

当我使用标准的“xml receive”管道接收到一个示例xml文档时,我可以看到所需的元素被按照预期提升到上下文中。

然后我创建了一个自定义管道,其中包含“反汇编”阶段中的“XML反汇编程序”组件和“验证”阶段中的自定义组件。这个自定义组件需要从上下文中读取提升的属性。但是,我发现当我将接收位置从“xml receive”管道切换到自定义管道时,我的属性没有得到提升。我用我的自定义组件中下面的代码写出来的项目在消息上下文的列表:

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)); 

从事件输出日志,我可以看到,某些性能,如消息类型得到了推广,但我自定义属性没有。同样,如果我将接收位置改回到使用标准的“xml接收”管道,那么属性将从同一个xml文档的副本升级(我通过停止订阅发送端口并从管理控制台查看上下文来检查该属性)。

我觉得这很奇怪,因为在相同的(默认)配置下,两个管道的“反汇编”阶段中存在相同的“XML反汇编程序”组件。我开始认为2013r2CU1可能存在问题 - 是否有其他人遇到过相同的问题?

回答

7

在您的自定义管道中执行XML反汇编程序时,不保证您的属性已被提升。

传入的消息以流的形式到达流水线,数据指针设置在流的开始位置。
我认为XML Disassembler不会读取流,它会将其封装到某个流封装类中,该流封装类将在流实际读取时填充提升的属性。
流必须至少读取一次:消息插入消息框时。所以可以保证属性会得到提升,但是不能认为它会在“验证”阶段执行之前完成。

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

解决方案:

为了使您的自定义管道组件工作时,最好的办法是做就像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) 
{ 
} 

解决您的问题将在您的自定义组件在“验证”阶段完全读取流,并把流指针回到一个不太有效的方法到流的开始。

微软,当你操纵的管道组件消息流的一些准则: https://msdn.microsoft.com/en-us/library/aa577699.aspx

更新:

OP需要消息上下文传递给事件处理程序。 有可能使用Lambda表达式: Pass parameter to EventHandler

+0

感谢您的详细回复加里,我想你可能是对的。我现在的问题是如何连接它。据我所知,AfterLastReadEvent委托不接受管道上下文 - 我需要能够访问。我对代表没有太多经验 - 你知道在事件发生时是否可以通过管道上下文吗? –

+0

@RobBowman是的,有可能。我已经更新了我的答案。我假设你想传递消息上下文而不是管道上下文。 –

+0

感谢您的更新加里。对不起,这让我很长时间,但目前我每天早上只有20分钟的时间来处理这个问题。你知道一个链接到一个EventingReadStream的例子吗?我一直无法找到一个。在我的“DoSomething”事件中,我现在拥有执行所需映射的代码。我现在的问题是我不知道如何将其分配回流。我应该将流作为ref参数传递给事件,那么对它的任何更新都会使它成为BizTalk的方式? –

2

你可以做任何你曾经在一个业务流程计划在验证阶段:

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) 
{ 
} 

这太问题可以通过附加参数为参考有趣?这会容易得多。

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

+0

是的,如果我不能使用事件性的阅读流工作,我可能不得不打破流水线,但我没有放弃:) :) –

+1

也许只是FYI,但Xml反汇编程序基本上使用事件来编写属性本身。你的问题是,直到元素被读取,相关的事件才会被触发。所以,如果你正在尝试一个事件模型,你可能会陷入与xmldasm相同的地方。 –