特集
次世代XML Webサービスを試す Part 3
SOAPメッセージのルーティング(後編)
5.WS-Referralを利用したルーティング(1)
インフォテリア株式会社
吉松 史彰
2003/02/27
|

|
WS-Referral
WSEを使ってサーバ側で経路を指定する方法は、独自にルータを実装する以外にもう1つある。WS-Referral仕様に基づくリファラル・キャッシュを利用する方法だ。WS-Referralとは、特定のSOAP actor(SOAPを処理できるサーバと考えてよい)を示すURIが、どのエンド・ポイントに存在するかを示す文書の書き方の仕様だ。WS-Referral仕様の日本語訳はマイクロソフトのホームページで参照できる(WS-Referral仕様の日本語訳)。WS-Referralも、2003年1月現在では、まだどの標準化団体にも提出されていない、Microsoftが提唱している独自仕様だ。
WS-Referral仕様では、次のようなリファラル文書の書き方を定義している。
<r:referrals
xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:ref>
<r:for>
<r:exact>http://localhost/WSERouting/Service1.asmx</r:exact>
</r:for>
<r:if />
<r:go>
<r:via>http://localhost/WSERouting/c.ashx</r:via>
</r:go>
<r:refId>uuid:8f18381e-36d7-483e-9512-4ee45ef7524c</r:refId>
</r:ref>
</r:referrals>
|
|
WS-Referral仕様によるリファラル文書の定義例 |
リファラル文書は、referralsという名前のルート要素を持ち、referralsには複数のrefという子要素を持つことができる。ref要素には5つの子要素が定義されている(下表)。要素はすべてhttp://schemas.xmlsoap.org/ws/2001/10/referralという名前空間に属している。
要素名 |
内容 |
必須 |
for |
あて先に指定されたSOAP actor |
○ |
if |
このリファラルが適用されるかどうかの条件 |
○ |
go |
forに指定されたactorを指すエンド・ポイント・アドレス |
○ |
refId |
このリファラルを一意に識別するID |
○ |
desc |
このリファラルの説明 |
× |
 |
表 WS-Referral仕様で定義されているリファラル文書の要素 |
例えば上記のリファラル文書は、
「http://localhost/WSERouting/Service1.asmxというSOAP actorにアクセスするには、http://localhost/WSERouting/c.ashxに転送すればよい」
という意味になる。if要素にはあて先以外の条件を指定できる。条件は独自に拡張して構わないが、WS-Referral仕様にはttl要素とinvalidates要素の2つが定義されている。ttl要素には有効期限となる時間(time-to-live)を、invalidates要素にはほかのリファラルのIDを指定して、それを無効化する効果がある(条件ではない)。
for要素には、子要素としてprefixとexactを設定することができる。上記はexactを指定しているので、指定されたURIと正確に一致するSOAPメッセージのみが対象となる。prefixを指定すると、「URIが〜で始まる場合」という指定をしたことになる。for要素にはprefixとexactを2つ以上設定できる。その場合はOR条件となる。
go要素には複数のvia子要素を設定できる。via子要素には通過点となるSOAPルータのアドレスを設定する。go要素にvia要素を複数設定した場合には、設定された中から1つだけが選択されて利用される。選択のアルゴリズムは決まっていない。
WSEとWS-Referral
WSEでは、WS-Referral仕様にのっとって記述された文書をファイルから読み取って、それを元にSOAPメッセージの経路を決める機能がある。この機能はWSEのデフォルトのルータ実装であるRoutingHandlerが持っている。RoutingHandlerは、次に述べる手順により、リファラル文書を読み取って経路を構成することができる。このルータを利用した、以下の図のようなパターンのXML Webサービスとそのクライアントを作成してみよう。
 |
リファラル文書によるルーティング |
ルータはリファラル文書を読み取り、XML Webサービスまでの経路を構成することができる。 |
Visual Studio .NET(以下VS.NET)でASP.NET Webサービス・プロジェクトを新しく作成する。ここでは名前を「WSERouting」とした。
VS.NETの「参照の追加」機能でMicrosoft.Web.Services.dllへ参照を追加する。
Service1.asmx.csファイルに次のようなWebMethodを記述する。
[WebMethod]
public string Echo(string input) {
return input;
}
|
|
Webサービスの本体となるメソッド |
Web.configファイルを編集して、system.web要素の子要素になるように次の要素を記述して、XML Webサービスの実行時にSoapExtensionが起動されるようにする。
<webServices>
<soapExtensionTypes>
<add type="Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0"/>
</soapExtensionTypes>
</webServices>
|
|
Web.configファイルでのSoapExtensionの設定 |
Webサービスの実行時にSoapExtensionが起動されるようにする。 |
Web.configファイルを編集して、configuration要素の直下に次の子要素を記述する。これによって、RoutingHandlerがリファラル文書を取得できるようになる。referral.xmlがリファラル文書の名前だ。
<configSections>
<section name="microsoft.web.services" type="Microsoft.Web.Services.Configuration.WebServicesConfiguration, Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<microsoft.web.services>
<referral>
<cache name="referral.xml" />
</referral>
</microsoft.web.services>
|
|
Web.configファイルによるリファラル文書の指定 |
Web.configと同じフォルダにreferral.xmlという名前のファイルを作成する。内容は次のようなリファラル文書だ。
<r:referrals xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:ref>
<r:for>
<r:exact>http://localhost/WSERouting/Service1.asmx</r:exact>
</r:for>
<r:if />
<r:go>
<r:via>http://localhost/WSERouting/c.ashx</r:via>
</r:go>
<r:refId>uuid:4f9f03e2-11b6-46d5-8677-122446c40042</r:refId>
</r:ref>
<r:ref>
<r:for>
<r:exact>http://localhost/WSERouting/c.ashx</r:exact>
</r:for>
<r:if />
<r:go>
<r:via>http://localhost/WSERouting/b.ashx</r:via>
</r:go>
<r:refId>uuid:87847570-df11-4e01-99db-1afd810bc4f7</r:refId>
</r:ref>
<r:ref>
<r:for>
<r:exact>http://localhost/WSERouting/b.ashx</r:exact>
</r:for>
<r:if />
<r:go>
<r:via>http://localhost/WSERouting/a.ashx</r:via>
</r:go>
<r:refId>uuid:b58c9200-2b8c-4710-9a5d-26c7cb5eb0f5</r:refId>
</r:ref>
</r:referrals>
|
|
リファラル文書となるreferral.xml |
Web.configと同じフォルダに作成する。 |
この文書では、Service1.asmxに対する要求はc.ashxを経由し、c.ashxに対する要求はb.ashxを経由し、b.ashxに対する要求はa.ashxを経由することになっている。つまり、
a.ashx → b.ashx → c.ashx → Service1.asmx
という経路が作成されることになる。
Web.configファイルを編集して、system.web要素の子要素になるように次の要素を記述して、HTTPハンドラをHTTPパイプラインに挿入する。
<httpHandlers>
<add type="WSERouting.NopRouter, WSERouting"
path="a.ashx" verb="*" />
<add type="WSERouting.NopRouter, WSERouting"
path="b.ashx" verb="*" />
<add type="WSERouting.NopRouter, WSERouting"
path="c.ashx" verb="*" />
<add type="Microsoft.Web.Services.Routing.RoutingHandler, Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" path="*.ashx" verb="*" />
</httpHandlers>
|
|
Web.configファイルでのHTTPハンドラの設定 |
各.ashxに対する処理クラスを記述している。a.ashx、b.ashx、c.ashxはNopRouterクラスが、それ以外の*.ashxに対してはRoutingHandlerクラスが処理を行う。 |
通常の*.ashxに対する要求はRoutingHandlerクラスが処理するが、a.ashx、b.ashx、c.ashxはNopRouterクラスが処理を行う設定になっている。NopRouterクラスの実装は次のようなものだ。要するに何もしないのである。
namespace WSERouting {
public class NopRouter : RoutingHandler {
protected override void ProcessRequestMessage(
SoapEnvelope message, Path outgoingPath) {}
protected override void
ProcessResponseMessage(SoapEnvelope message) {}
}
}
|
|
NopRouterクラスの実装 |
このクラスは何もしないルータを記述している。 |
RoutingHandlerは、呼び出されるたびにWeb.configの設定を確認してリファラル文書から経路を作成しようとする。つまり、a.ashx、b.ashx、c.ashxに対してRoutingHandlerが処理を行ってしまうと、すでに設定してある経路に対してさらに経路を設定することになり、経路がループしてしまう。最初に作成された経路を使ってあとは処理を転送するだけにするために、何もしないルータをRoutingHandlerとは別に用意してそれを指定しているわけだ。今回はすべてのルータが同じ拡張子を利用しているため、拡張子で処理を分けているASP.NETでは違いを判断できない。仕方なくこのようなハッキングを行っている。