2

これが状況です。15分ごとに実行される一連の12の統合タスクがあり、それらのほとんどは実際にOracleサーバーから何かを読み取り、それをWebサービスにプッシュします。oracleサービスとWebサービスの両方のポートを作成し、15分ごとにループし、タスクを実行する他のオーケストレーションを呼び出すメインオーケストレーションを作成しました。

さて、私の問題は、これらのオーケストレーションがメッセージの到着によって呼び出されないことです。オラクルポートに送信するメッセージを作成する必要があります。次のようになります。

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

ノード値がどうなるかはわかりますが、「マジックストリング」を使用し、LoadXmlを使用してxmlDocにロードする文字列を連結し、それをメッセージパラメータに割り当てる以外に、メッセージを作成する方法がわかりません。多くの理由で回避するため(将来の名前空間の変更から開始)。オーケストレーションで「空白」のメッセージを作成し、それを入力する方法はありますか?

質問は非常に単純で、森から木を見ることができないかもしれませんが、ネット上で見たすべてのサンプルは単純化されており(つまり、誰かが監視対象のフォルダーに準備ができたxmlをドロップしてオーケストレーションを呼び出すだけです)、助けにはなりません。

4

4 に答える 4

2

同様の問題に対して実装した解決策は次のとおりです。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 doc MyTemplate.xmlをプロジェクトに追加し、コンパイルアクションをに変更してEmbedded Resource、ResorceXmlDocumentがReflectionを介してロードできるようにします。

<?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を作成するConstructMessageShape内

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;

私はutillibを保持ResourceXmlDocumentQueryValuesていて、必要なBizTalkプロジェクトから参照しています。さまざまなXmlテンプレートドキュメントがそれぞれのBizTalkアセンブリに埋め込まれています。

OPによる編集:実際、これを機能させる唯一の方法は、OuterXmlのカスタムシリアル化を使用してメッセージを実装ISerializableして永続化することです。ResourceXmlDocumentベースの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);
    }
于 2012-02-01T15:14:11.810 に答える
2

XmlDocumentのタイプを返す静的ヘルパー関数を作成します。割り当てシェイプ内からこの関数を呼び出します。

ヘルパー関数内で、構成ファイルまたはテキストファイルから設定(名前空間など、またはメッセージ全体)をロードできます。

ベストプラクティスとして、この設定をSSOに保存する必要があります。これについてサポートが必要な場合はお知らせください。

于 2012-02-01T14:36:53.850 に答える
1

Yossi Dahanは、これらのメソッド(マップ、割り当て、および文書化されていないAPIの使用)をここで比較します

APIメソッドはMicrosoft.BizTalk.Component.Interop.DocumentSpecを使用します-ここここを参照しますが、Yossiが言及しているように、マップやXmlDocument.LoadXmlよりもはるかに低速です

使用法に関する注意事項:

  • アセンブリはTestSchema、Version = 1.0.0.0、Culture = neutral、publicKeyToken =xxxxxxxxxxxxxxxx"です。
  • schemaNameはTestSchema.MyTestSchema[+myRootNode1]
  • バージョンに依存することに注意してください-アセンブリバージョンが変更された場合、バージョン文字列も更新しない限り、作成は失敗します。
  • この方法で作成された新しいメッセージは、XSDに対して必ずしも有効であるとは限りません。たとえば、DateTimesとIntsは、たとえそれらがnillableであっても、空の要素になります(これにより、XMLでnillable = trueが設定されません)
于 2012-02-01T15:22:01.557 に答える
0

変換シェイプを使用して、ORACLEに送信するスキーマのインスタンスを作成することを検討しましたか?

これは、メッセージ割り当てシェイプでメッセージを作成する代わりの方法の1つです。詳細が必要な場合はお知らせください。

HTH

于 2012-02-01T14:01:55.767 に答える