問題を解決するための標準的な方法は、実際、着信パイプラインのデコード段階でカスタムパイプラインコンポーネントを使用することです。
これを効率的に機能させるための2つの方法があります。
BizTalkESBTookitパイプラインコンポーネントの使用
BizTalk ESB Toolkit 2.1には、着信メッセージのXML名前空間を操作するための非常に強力なパイプラインコンポーネントのセットがあります。このパイプラインは、Microsoft.Practices.ESB.Namespace.PipelineComponents.dllアセンブリで利用でき、インストール時にVisualStudioツールボックスで利用できるようになります。
これらのコンポーネントの以前のバージョンは、MSDNに記載されています。このドキュメントはかなり古くなっていますが、新しいバージョンでは何も変わっていないと思います。それでも、適切な使用法と参照については、さまざまなフォーラムの質問を参照することをお勧めします。
単純なAddXmlNamespaceパイプラインコンポーネントの構築
ご使用の環境にBizTalkESBToolkitをインストールしたくない、またはインストールできない場合は、コンポーネントの簡略化されたバージョンを自分で作成することをお勧めします。活用できるBizTalkランタイムの組み込みクラスのおかげで、それはまったく難しいことではありません。
質問で示したコードは、適切なストリーミング対応のパイプラインコンポーネントに準拠していないため、以下に必要なコードを示しています。以下に示すコードは、元のルートタグにXML名前空間がまだ存在しない場合は、それを追加することのみを扱っていることに注意してください。
まず、元のドキュメントのルートタグにXML名前空間とプレフィックスを追加することを処理する単純なSystem.IO.Streamから派生したクラスを構築する必要があります。
ストリーミングをサポートするために、コードはMicrosoft.BizTalk.Streaming.XmlTranslatorStreamクラスを利用します。このクラスはSAXのようなインターフェースを示し、XML解析段階のさまざまなポイントで実装のオーバーライドが呼び出されます。これらはすべて、任意の大きなドキュメントのストリーミングを完全にサポートしながら実行されます。
これはコードです:
using Microsoft.BizTalk.Streaming;
public class AddXmlNamespaceStream : XmlTranslatorStream
{
private String namespace_;
private int level_ = 0; // hierarchy level
public AddXmlNamespaceStream(Stream stream, String @namespace)
: base(XmlReader.Create(stream))
{
namespace_ = @namespace;
}
#region XmlTranslatorStream Overrides
protected override void TranslateStartElement(string prefix, string localName, string nsURI)
{
if (level_++ != 0)
{
base.TranslateStartElement(prefix, localName, nsURI);
return;
}
if (String.IsNullOrEmpty(nsURI))
{
nsURI = namespace_;
if (String.IsNullOrEmpty(prefix))
prefix = "__bts_ns0__";
}
base.TranslateStartElement(prefix, localName, nsURI);
}
protected override void TranslateEndElement(bool full)
{
if (level_-- != 0)
{
base.TranslateEndElement(full);
return;
}
base.TranslateEndElement(full);
}
#endregion
}
このクラスはTranslateStartElementメソッドとTranslateEndElementメソッドの両方をオーバーライドしますが、階層の最初のレベル(ルートタグ)の要素のみを処理することに気付くでしょう。他のすべての要素は、基本クラスによって提供されるデフォルトの何もしない特別な動作に従って処理されます。
パイプラインコンポーネント自体については、必要なボイラープレートインフラストラクチャコードをすべてすでにセットアップしている可能性があるため、ここではExecuteメソッドのみを示します。そうでない場合は、下から順に次の場所にあるブログ投稿を参照してください。
ここにあります:
public class AddXmlNamespace : ..., IComponent
{
#region Design-Time Properties
public String Namespace { get; set; }
#endregion
#region IComponent Implementation
public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
var stream = new AddXmlNamespaceStream(
pInMsg.BodyPart.GetOriginalDataStream()
, Namespace);
pInMsg.BodyPart.Data = stream;
pContext.ResourceTracker.AddResource(stream);
return pInMsg;
}
#endregion
...
}
ご覧のとおり、Executeメソッドによって実行される唯一のアクションは、元のストリームを新しいAddXmlNamespaceストリームクラスのインスタンスでラップし、着信メッセージストリームを置き換えるように接続することです。
お役に立てれば。