SOAP ヘッダーの定義と使用
SOAP コード化された Web サービス アプリケーションへの要求やアプリケーションからの応答には、一連のヘッダー ノードが含まれています。SOAP Action ヘッダーなど、ヘッダー ノードの中には自動的に生成されて解釈されるものがあります。ただし、自分でヘッダーを定義して、サーバーとクライアント間の通信をカスタマイズすることもできます。通常、これらのヘッダーには、1 つのメッセージの件名であるメソッドだけでなく、起動可能インターフェイス全体またはアプリケーション全体に関連する情報が含まれています。
ヘッダー クラスの定義
定義するヘッダーごとに、Soap.InvokeRegistry.TSOAPHeader の下位クラスを作成します。TSOAPHeader は、TRemotable の下位クラスです。つまり、SOAP ヘッダー オブジェクトは、リモート可能オブジェクトの単なる特殊型だと言えます。リモート可能オブジェクトの場合と同様に、TSOAPHeader 下位クラスにパブリッシュ プロパティを追加すれば、ヘッダーがやり取りする情報を表すことができます。SOAP ヘッダー クラスを定義したら、リモート可能型レジストリに登録する必要があります。その他のリモート可能クラスの場合、起動可能インターフェイスを登録すると、そのインターフェイスで使用されるリモート可能クラスも自動的に登録されますが、SOAP ヘッダークラスの場合はヘッダー タイプを登録するコードを明示的に記述する必要があります。
TSOAPHeader は、SOAP ヘッダー ノードの属性を表す 2 つのプロパティを定義します。それが、MustUnderstand と Actor です。MustUnderstand 属性が True の場合、このヘッダーを含むメッセージを受け取った受信者は受信確認を送信する必要があります。MustUnderstand 属性を含むヘッダーを解釈できない場合、受信者はそのメッセージ全体の解釈を中止する必要があります。MustUnderstand 属性が設定されていないアプリケーションでは、ヘッダーを無視しても問題になりません。MustUnderstand の使用は、Actor プロパティで指定します。Actor は、ヘッダーの宛先となるアプリケーションを識別する URI です。たとえば、Web サービス アプリケーションが別のサービスに処理の要求を送信する場合に、クライアント メッセージの一部のヘッダーをそのサービスに送ることができます。このヘッダーに MustUnderstand 属性が含まれていたら、たとえアプリケーションがヘッダーを認識できなくても、要求を中止してはなりません。アプリケーションは Actor 属性でその URL を指定するヘッダーだけを認識します。
ヘッダーの送受信
ヘッダー クラスを定義して登録したら、アプリケーションで使用できます。アプリケーションが要求を受け取ると、メッセージ上のヘッダーは対応する定義済みの TSOAPHeader 下位クラスに自動的に変換されます。アプリケーションは、ヘッダー ノードの名前と、ヘッダー クラスの登録時に指定された型名または起動レジストリにヘッダー クラスを登録したときに指定された名前を照合して、適切なヘッダー クラスを識別します。アプリケーションがリモート可能型レジストリで一致する名前を見つけられない場合、そのヘッダーは無視されます。MustUnderstand 属性が True に設定されている場合には、アプリケーションは SOAP エラーを生成します。
アプリケーションが受け取ったヘッダーは、Soap.InvokeRegistry.ISOAPHeaders インターフェイスでアクセスできます。このインターフェイスを起動する方法は 2 とおりあり、TInvokableClass のインスタンスから起動する方法と、TInvokableClass なしで起動可能インターフェイスを実装している場合のグローバル関数 GetSOAPHeaders を使用する方法があります。
ISOAPHeaders の Get メソッドで名前からヘッダーにアクセスします。以下に例を示します。
TServiceImpl.GetQuote(Symbol: string): Double; var Headers: ISOAPHeaders; H: TAuthHeader; begin Headers := Self as ISOAPHeaders; Headers.Get(AuthHeader, TSOAPHeader(H)); { Retrieve the authentication header } try if H = nil then raise ERemotableException.Create("SOAP header for authentication required"); { code here to check name and password } finally H.Free; end; { now that user is authenticated, look up and return quote } end;
アプリケーションで生成される要求メッセージに対する応答にヘッダーを含める場合にも、同じインターフェイスを使用できます。ISOAPHeaders は、送信応答にヘッダーを追加する Send メソッドを定義します。送信するヘッダーに対応する各ヘッダー クラスにインスタンスを作成し、プロパティを設定し、Send を呼び出します。
TServiceImpl.GetQuote(Symbol: string): Double; var Headers: ISOAPHeaders; H: TQuoteDelay; TXSDuration Delay; begin Headers := Self as ISOAPHeaders; { code to lookup the quote and set the return value } { this code sets the Delay variable to the time delay on the quote } H := TQuoteDelay.Create; H.Delay := Delay; Headers.OwnsSentHeaders := True; Headers.Send(H); end;
スカラ型ヘッダーの処理
Web サービスの中には、リモート可能タイプのような複雑な構造ではなく、整数や文字列などの単純型を定義して使用するサービスがあります。ただし、Delphi の SOAP ヘッダーのサポートでは、TSOAPHeader の下位クラスを使ってヘッダー タイプを表す必要があります。単純型のヘッダー クラスを定義するには、TSOAPHeader クラスをホルダ クラスとして扱います。つまり、TSOAPHeader の下位クラスには 1 つのパブリッシュ プロパティが含まれ、これが実際のヘッダーの型になります。SOAP の表現に TSOAPHeader の下位クラスを含める必要がないことを知らせるには、ヘッダー タイプを登録した後でリモート可能型レジストリの RegisterSerializeOptions メソッドを呼び出して、ヘッダー タイプに xoSimpleTypeWrapper オプションを指定します。
他のアプリケーションへのヘッダー構造の通知
アプリケーションでヘッダーを定義する場合、そのクライアントがこれらの定義にアクセスできるようにする必要があります。クライアントが Delphi で記述されている場合には、ヘッダー クラスを定義および登録するユニットをクライアント アプリケーションと共有できます。ただし、他のクライアントにも使用するヘッダーについて知らせておく必要があります。アプリケーションがそのヘッダー クラスについての情報をエクスポートできるようにするには、ヘッダー クラスを起動レジストリに登録する必要があります。ヘッダー クラスを登録すると、そのクラスと名前空間に定義されたヘッダー名の関連付けも行われます。
起動可能インターフェイスを登録するコードと同様に、エクスポート用のヘッダー クラスを登録するコードも、ヘッダー クラスが定義されているユニットの初期化セクションに追加されます。グローバル関数 InvRegistry を使用し、起動レジストリまでのリファレンスを取得し、ヘッダーを関連付けるインターフェイスを指定して、その RegisterHeaderClass メソッドを呼び出します。
initialization InvRegistry.RegisterInterface(TypeInfo(IMyWebService)); {register the interface} InvRegistry.RegisterHeaderClass(TypeInfo(IMyWebService), TMyHeaderClass); {and the header} end.
static void RegTypes() { // register the invokable interface: InvRegistry()->RegisterInterface(__delphirtti(IMyService), "", ""); // register the header to be used with it: InvRegistry()->RegisterHeaderClass(__delphirtti(IMyService), __classid(TMyHeader)); } #pragma startup RegTypes 32
この後で RegisterHeaderMethod メソッドを呼び出して、インターフェイス上のメソッドの一部にヘッダーを限定することができます。
メモ: implementation セクションの uses 句には、InvRegistry 関数が定義されるように InvokeRegistry ユニットを含める必要があります。
起動レジストリにヘッダー クラスを登録して、Web サービスを公開すると、その記述が WSDL ドキュメントに追加されます。
メモ: ヘッダー クラスは、リモート可能型レジストリに登録して、さらに起動レジストリにも登録する必要があります。