【问题标题】:BizTalk envelope schema self-closing nodeBizTalk 信封架构自闭合节点
【发布时间】:2014-03-31 16:24:13
【问题描述】:

我创建了一个 BizTalk 接收位置,它有一个订阅发送端口,它接受封装的消息并仅使用 XML 接收管道拆分成单独的消息。

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace">
    <MyData>ABC</MyData>
    <MyData>DEF</MyData>
    <MyData>GHI</MyData>
</MyEnvelope>

保存为

<?xml version="1.0" encoding="utf-8"?>
<MyData xmlns="MyNameSpace">ABC</MyData>

,

 <?xml version="1.0" encoding="utf-8"?>
 <MyData xmlns="MyNameSpace">DEF</MyData>

 <?xml version="1.0" encoding="utf-8"?>
 <MyData xmlns="MyNameSpace">GHI</MyData>

太棒了。

但是,当消息中没有元素时,服务会发送带有自闭合和空信封的消息:

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace"/>

我收到错误消息

来源:“XML 反汇编程序”接收端口:“InLocation”URI: “c:\MyLocation*.xml” 原因:处于状态的意外事件 (“eos”) “处理头”。

如果我手动创建一条不是自动关闭的消息:

<?xml version="1.0" encoding="utf-8"?>
<MyEnvelope xmlns="MyNameSpace"></MyEnvelope>

我没有错误。我的处理不受这些错误的影响,但它一定会对性能产生一些影响,并且会在 Group Hub 暂停实例视图中乱扔垃圾。

BizTalk 似乎将自闭合节点解释为空格而不是 null。这似乎与my issues with attempting to call a service with no parameters 相关联,我需要在其中发送一个自动关闭节点,但 BizTalk 什么也没发送。

处理没有内容的信封一定是一个常见问题。如何配置我的应用程序以使用自闭合信封节点接收和忽略这些消息?

【问题讨论】:

  • 如果您从某个服务接收该消息,那么如果没有要发送的内容,您最好让该服务不发送任何内容:) 否则,如果您正在从数据库(?)轮询数据并使用 inboundOperationType = XmlPolling,那么您应该在接收位置(RL 绑定中的 xmlStoredProcedureRootNodeName 参数)中而不是在轮询语句中附加 MyEnvelope 标头。如果您没有要轮询的数据,那么您的轮询过程应该返回零行。
  • @ArsenMagomedov 如果您可以访问该服务,这没关系。信封实际上是一个集合。我假设它在迭代项目之前被初始化。如果我有权访问,我只能在有数据要返回的情况下初始化集合。这将解决我的问题,但并不能真正回答有关 BizTalk 的问题

标签: xml biztalk biztalk-2013


【解决方案1】:

他们似乎经常改变处理空白的行为。见Change in Default Whitespace Behavior in BizTalk。我不确定您的问题是否相关,但值得一看。它没有提到 BizTalk 2013,但设置在主机中。如果您进行此配置设置,则需要专门为它设置一个主机,这样它就不会影响其他现有应用程序(如果有的话)。

安装以下更新之一会导致 BizTalk 更改默认行为以在映射期间保留 XML 中的空白:

  1. BizTalk 2010 CU1 或更高版本
  2. BizTalk 2009 CU3 或更高版本
  3. BizTalk 2006 R2 SP1 CU4 或更高版本
  4. 修补程序 2492255

在某些环境中,转换删除空格可能是首选。为了恢复这种行为,可以采取以下步骤:

在 BizTalk 2010 中,这是在主机级别设置的:

  1. 打开 BizTalk Server 管理控制台
  2. 将 BizTalk 组扩展到平台设置 > 主机
  3. 右键单击主机并选择设置
  4. 选中旧版空白行为旁边的复选框
  5. 点击确定
  6. 重新启动此主机的 BizTalk 主机实例

在 BizTalk 2009 和 2006 R2 中,此值在每台计算机级别设置:

  1. 打开注册表编辑器
  2. 在基于 x86 的计算机上找到并单击以下注册表子项: • HKEY_LOCAL_MACHINE\Software\Microsoft\BizTalk Server\3.0\Administration 对于基于 x64 的计算机,请单击以下注册表子项: • HKEY_LOCAL_MACHINE\Software\Microsoft\BizTalk Server\3.0\Administration
    • HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\BizTalk Server\3.0\Administration
  3. 右键单击并选择 DWORD 值。
  4. 键入 LegacyWhitespace 作为值名称,然后双击它并将值数据设置为 1。
  5. 退出注册表编辑器。
  6. 重新启动此计算机上的 BizTalk 主机实例

【讨论】:

  • 不,我仍然遇到同样的错误。我不确定这是否相关,因为消息是在 BizTalk 之外创建的,我想这会影响 BizTalk 创建而不是消费的消息。
【解决方案2】:

我没有看到或验证过这种行为,但我相信你;)。

除非您每小时获得 10K 文件或类似情况,否则不要担心异常对性能的影响。

为防止出现错误,您必须取消或重新格式化管道组件中的消息。

【讨论】:

  • 使用管道也是我的第一个想法。我基本上只想在信封有子节点时调用 xml 反汇编程序,尽管我正在努力寻找如何做到这一点的体面示例。我有创建独立组件的示例,但我只想对 XMLReceive 做一点小改动。我不想重写这个并且有维护它的麻烦。
【解决方案3】:

我知道这是一个老问题,但我也遇到过同样的事情(特别是在返回空结果集的 SQL XML 轮询/过程中)。通常我通过确保如果 SQL 返回一个空的结果集(优化 Data Available 语句)就不会调用它来绕过它,但有时它并不完全可能或万无一失。最后,我在解码阶段编写了一个自定义管道组件。它旨在执行以下操作:

  1. 检查这是否是一个信封模式(这个错误应该发生的唯一时间
  2. 尽量容忍 BizTalk 是格式错误的 XML(至少对于 XML 中的无效字符而言)
  3. 检查第一个内容元素(即根元素)是否为空
  4. 如果是这样,用“FullEndElement”重写它。
  5. 重置流并将它们添加到资源跟踪器以进行最终处理
  6. 在异常情况下,悄悄地写入调试跟踪器,但让 BizTalk 从那里获取它 - 最坏的情况是产生嘈杂但无害的错误消息。
Stream origStream = pInMsg.BodyPart.GetOriginalDataStream();
try
{
    XmlReaderSettings readerSettings = new XmlReaderSettings();
    readerSettings.CheckCharacters = false; 
    readerSettings.CloseInput = false;

    XmlReader reader = XmlReader.Create(origStream, readerSettings);
    pContext.ResourceTracker.AddResource(reader);

    reader.MoveToContent();

    IDocumentSpec docSpec = pContext.GetDocumentSpecByType(reader.NamespaceURI + "#" + reader.LocalName);
    if (!string.IsNullOrWhiteSpace(docSpec.GetBodyPath()) && reader.IsEmptyElement) // this is an envelope schema with an empty root node
    {
        XmlWriterSettings writerSettings = new XmlWriterSettings();
        writerSettings.CheckCharacters = false;
        writerSettings.OmitXmlDeclaration = true;

        MemoryStream ms = new MemoryStream(); // for such a small stream, MemoryStream is perfectly fine - normally use VirtualStream.
        pContext.ResourceTracker.AddResource(ms);

        XmlWriter writer = XmlWriter.Create(ms, writerSettings);
        pContext.ResourceTracker.AddResource(writer);

        writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
        writer.WriteFullEndElement();
        writer.Flush();

        ms.Position = 0;
        pInMsg.BodyPart.Data = ms;
    }
}
catch (Exception e)
{
    // swallow exception 
    System.Diagnostics.Debug.WriteLine(e.ToString());
}
finally // make sure we're somewhat well behaved
{
    if (pInMsg.BodyPart.Data.CanSeek == true)
        pInMsg.BodyPart.Data.Position = 0;
}

【讨论】:

    【解决方案4】:

    另一个(非常)迟到的答案。它并没有真正回答 OP 的问题,但是由于我在这里谷歌搜索错误消息并最终导致我找到了这个解决方案,所以我想无论如何我都会回答,以防它帮助其他人。

    如果您可以像我一样控制信封的结构,您可以在信封中添加另一个级别,如果它是自动关闭的,则不会导致错误。

    所以,这会导致错误:

    <MyEnvelope xmlns="MyNameSpace" />
    

    但这不会:

    <MyEnvelope xmlns="MyNameSpace">
      <Body />
    </MyEnvelope>
    

    将架构的 Body XPath 设置为此嵌套级别,它应该可以正常处理。

    <MyEnvelope xmlns="MyNameSpace">
        <Body>
            <MyData>ABC</MyData>
            <MyData>DEF</MyData>
            <MyData>GHI</MyData>
        </Body>
    </MyEnvelope>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-16
      • 2010-12-25
      • 2023-03-26
      • 1970-01-01
      相关资源
      最近更新 更多