【问题标题】:Manually constructing a message inside orchestration在编排中手动构建消息
【发布时间】:2012-02-01 11:32:33
【问题描述】:

这里的情况。 我有 12 个集成任务序列,每 15 分钟运行一次,其中大多数实际上是从 oracle 服务器读取某些内容并将其推送到 Web 服务中。我为 oracle 和 web 服务创建了一个端口,并创建了一个主编排,它每 15 分钟循环一次,并调用将执行其任务的其他编排。

现在,我的问题是消息到达不会调用这些编排,我需要构造一条消息,将其发送到 oracle 端口。看起来像这样的那个:

<Select xmlns="http://Microsoft.LobServices.OracleDB/2007/03/HR/Table/EMPLOYEES">
    <COLUMN_NAMES>*</COLUMN_NAMES>
    <FILTER>DATE=somedate</FILTER>
</Select>

我知道节点值是什么,但我不知道如何构造消息,除了使用“魔术字符串”和连接字符串,我将使用 LoadXml 加载到 xmlDoc 中,然后将其分配给我会的消息参数出于很多原因非常想避免(从将来更改命名空间开始)。有没有办法让编排创建我将填写的“空白”消息?

也许问题很简单,我看不到森林里的树,但是我在网上看到的所有示例都被简化了(意味着有人只是将准备好的 xml 放在监视文件夹中以调用编排)并执行不帮我。

【问题讨论】:

    标签: oracle11g biztalk biztalk-2010


    【解决方案1】:

    这是我针对类似问题实施的解决方案:正如 Hugh 建议的那样,我使用从 XmlDocument 继承的帮助程序。

    Xml 模板类

    using System;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Xml;
    
    namespace Acme
    {
        [Serializable]
        public class ResourceXmlDocument : XmlDocument
        {
            public ResourceXmlDocument(Type assemblyType, string resourceName, QueryValues queryValues)
            {
                try
                {
                    Assembly callingAssembly = Assembly.GetAssembly(assemblyType);
    
                    if (null == callingAssembly)
                    {
                        throw new ResourceException("GetExecutingAssembly returned null");
                    }
    
                    Stream resourceStream = callingAssembly.GetManifestResourceStream(resourceName);
    
                    Load(resourceStream);
    
                    if (null == queryValues)
                    {
                        throw new ResourceException("queryValues not initialized");
                    }
    
                    if (queryValues.Keys.Count < 1)
                    {
                        throw new ResourceException("queryValues.Keys must have at least one value");
                    }
    
    
                    foreach (string querycondition in queryValues.Keys)
                    {
                        XmlNode conditionNode = this.SelectSingleNode(querycondition);
    
                        if (null == conditionNode)
                        {
                            throw new ResourceException(string.Format(CultureInfo.InvariantCulture, "Condition: '{0}' did not return a XmlNode", querycondition));
                        }
    
                        XmlAttribute valueAttribute = conditionNode.Attributes["value"];
    
                        if (null == valueAttribute)
                        {
                            throw new ResourceException(string.Format(CultureInfo.InvariantCulture, "Condition: '{0}' with attribute 'value' did not return an XmlAttribute ", querycondition));
                        }
    
                        valueAttribute.Value = queryValues[querycondition];
                    }
                }
                catch (Exception ex)
                {
                    throw new ResourceException(ex.Message);
                }
            }
        }
    }
    

    当然,我的示例针对要设置的固定属性 value,因此您必须根据自己的需要进行调整。

    QueryValues 帮助类

    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    
    namespace Acme
    {
        [Serializable]
        public class QueryValues : Dictionary<string, string>
        {
            public QueryValues()
            {
            }
    
    
            protected QueryValues(SerializationInfo info, StreamingContext context) : base(info, context)
            {
            }
        }
    }
    

    Xml 模板

    向您的项目添加一个 Xml 文档 MyTemplate.xml 并将编译操作更改为 Embedded Resource,以便 ResorceXmlDocument 可以通过反射加载它。

    <?xml version="1.0" encoding="utf-8" ?>
    <root>
        <SomeOtherNode>some (fixed) value</SomeOtherNode>
        <MyNodeName tablename="MyTableName" fieldname="MyFieldName" value="0" />
        <YetAnotherNode>
            <SubNode>Foo</SubNode>
        </YetAnotherNode>
    </root>
    

    编排变量和消息

    你需要声明

    • `Acme.QueryValues` 类型的变量 *queryValues*
    • `Acme.ResourceXmlDocument` 类型的变量 *resourceXmlDoc*
    • `MySchemaType` 类型的消息

    将其放在消息分配形状中

    在构造消息形状中创建 MySchemaType 类型的消息 MyRequest

    queryValues = new Acme.QueryValues();
    
    queryValues.Add("//MyNodeName[@tablename='MyTableName' and @fieldname='MyFieldName']", "MyValueToSet");
    
    resourceXmlDoc = new Acme.ResourceXmlDocument(typeof(Acme.MySchemaType), "MyTemplate.xml", queryValues);
    
    MyRequest = resourceXmlDoc;
    

    我将ResourceXmlDocumentQueryValues 保存在一个实用程序库中,并从我需要的任何BizTalk 项目中引用它。各种 Xml 模板文档嵌入到各自的 BizTalk 程序集中。

    由 OP 编辑​​: 实际上,我进行这项工作的唯一方法是在 ResourceXmlDocument 上实现 ISerializable,并使用 OuterXml 的自定义序列化来持久化消息。基础中的 XmlDocument 本身根本无法序列化。如果有其他方法,请随时编辑。

    [Serializable]
    public class ResourceXmlDocument : XmlDocument, ISerializable
    {
    
        ...
    
        protected ResourceXmlDocument(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new System.ArgumentNullException("info");
            Load(info.GetString("content"));
        }
    
    
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new System.ArgumentNullException("info");
            info.AddValue("content", this.OuterXml);
        }
    

    【讨论】:

    • @nonnb 总是乐于提供帮助。事实证明,它在我们的环境中是一个非常强大的解决方案。
    • 我会试试这个,但我刚刚发现了一些东西。当我展示所有消耗适配器的文件时,我发现了一个不属于项目的 .cs 文件。该文件包含所有架构元素的可序列化类(Microsoft.BizTalk.Schema.Compiler 自动生成,3.0.1.0)。但是,如果我包含该文件,它仍然看不到它的分配形状。
    • @mmix 您需要声明这种类型的变量(编排视图)才能在您的分配形状中使用它。
    • 不,声明 var 不起作用,出于同样的原因 Hugh 的建议不起作用。看来您的解决方案是唯一合理的解决方案,这是 Biztalk 非常奇怪的限制,恕我直言。他们真的如此脱离现实,以至于他们认为没有人愿意从头开始创建信息吗?无论如何,为了保持一致性,我会尝试你的建议,如果可行,我会接受这个答案。
    • @mmix 好吧,基本上每个 Construct Message Shape 都会从头开始创建一条消息 - 在您的情况下,棘手的部分是填写值(而不是映射或复制源消息)。如果您提升每个字段(仅当它们是非重复节点时才有效),您可以简单地分配值。
    【解决方案2】:

    创建一个返回 XmlDocument 类型的静态辅助函数。从您的分配形状中调用此函数。

    在辅助函数中,您可以从配置或文本文件加载设置(命名空间等,甚至是完整消息)。

    为了获得最佳实践,您应该将此配置存储在 SSO 中。如果您需要这方面的帮助,请告诉我。

    【讨论】:

    • 这不需要外部库吗?如果是这样,如何在项目之间保持 xsd 模式同步?你有一些我可以学习的教程吗?
    • 如果您不想要外部程序集,可以在与编排相同的程序集中创建静态帮助程序。
    • 我正要问怎么做,但后来我复制/粘贴了一个 cs 文件……它似乎构建好了。这也将对我在其他方面有所帮助,所以我现在就投赞成票。
    • 其实,不开心,该类在bt项目中,它没有抱怨它,但在分配形状中我看不到类型。
    • 您确定该类与您的编排类型在同一个命名空间中吗?
    【解决方案3】:

    Yossi Dahan 比较了这些方法(映射、分配和使用未记录的 API)here

    API 方法使用 Microsoft.BizTalk.Component.Interop.DocumentSpec - 引用 herehere,但正如 Yossi 所提到的,它比地图或 XmlDocument.LoadXml 慢得多

    只是一些使用说明:

    • Assembly 是 TestSchema,Version=1.0.0.0,Culture=neutral,publicKeyToken=xxxxxxxxxxxxxxxx”;
    • schemaName 是 TestSchema.MyTestSchema[+myRootNode1]
    • 注意取决于版本 - 如果程序集版本更改,则创建将失败,除非同时更新版本字符串。
    • 以这种方式创建的新消息不一定对 XSD 有效。例如DateTimes 和 Ints 将只是空元素,即使它们是可空的(这不会在 XML 中设置 nillable=true)

    【讨论】:

    • Yossi 会说话,但不会走路,我猜他认为我们都处于这个水平。也许有一天,但不是今天,因为他没有制作任何样品,我真的不知道如何使用他的建议。至于第二个,我不想使用未记录的功能(多年后它们总是会导致讨厌的电话)
    【解决方案4】:

    您是否考虑过使用变换形状来创建要发送到 ORACLE 的架构实例?

    这是在消息分配形状中创建消息的一种替代方法。 如果您需要更多详细信息,请告诉我!

    HTH

    【讨论】:

    • 转换需要源消息,而我没有。
    猜你喜欢
    • 2010-11-18
    • 1970-01-01
    • 2015-06-21
    • 2014-11-08
    • 2022-06-10
    • 2011-03-28
    • 2019-01-04
    • 2023-03-30
    • 2021-06-29
    相关资源
    最近更新 更多