新しい Web サービスの追加
Web サービスの使用:インデックス への移動
新しい Web サービスインターフェースをサーバーアプリケーションに追加するには,[ファイル > 新規作成 > その他]を選択し,[WebServices]ページで[SOAP サーバーインターフェース]アイコンをダブルクリックします。
[Web サービスの新規作成]ウィザードでは,クライアントにエクスポーズする起動可能インターフェースの名前を指定できます。また,このインターフェースとその実装クラスを宣言し,登録するコードが生成されます。デフォルトでは,サンプルのメソッドと追加の型定義を示すコメントも生成されるので,生成されたファイルの編集に着手しやすくなっています。
生成されたコードの編集
生成されたユニットのインターフェース部にインターフェース定義が表示されます。この生成されたユニットには,ウィザードで指定した名前が付いています。インターフェース宣言を変更するには,サンプルのメソッドを置き換えて,クライアントが使用できるようにするメソッドにします。
Soap.InvokeRegistry.TInvokableClass と起動可能インターフェースを継承し,起動可能インターフェースをサポートする実装クラスがウィザードによって生成されます。まったく最初から起動可能インターフェースを定義する場合は,実装クラスの宣言を編集して,生成された起動可能インターフェースに行った編集と一致させなければなりません。
起動可能インターフェースと実装クラスにメソッドを追加するときは,そのメソッドではリモート可能な型だけを使用しなければならないことに注意してください。リモート可能な型と起動可能インターフェースについては,「起動可能インターフェースでの非スカラー型の使用」を参照してください。
異なる基本クラスの使用
[Web サービスの新規追加]ウィザードは,TInvokableClass を継承する実装クラスを生成します。Web サービスを実装する新しいクラスを作成する方法としてはこれが最も簡単です。ただし,この生成されたクラスは,異なる基本クラスを持つ実装クラスで置き換えることができます(たとえば,既存のクラスを基本クラスとして使用できます)。生成された実装クラスを置き換えるときは,以下のようにいくつか考慮すべきポイントがあります。
- 新しい実装クラスは,起動可能インターフェースを直接サポートする必要があります。起動可能インターフェースとその実装クラスが登録される起動レジストリは,登録された各インターフェースをどのクラスが実装するかを追跡し,インボーカがインターフェースを呼び出す必要ができたときにインボーカコンポーネントが使用できるようにします。クラス宣言にインターフェースが直接含まれる場合,あるクラスがそのインターフェースを実装したことしか検出できません。基本クラスとともに継承された場合は,インターフェースのサポートは検出されません。
- 新しい実装クラスは,インターフェースの一部である IInterface メソッドのサポートを含まなければなりません。このことは言うまでもないように思えますが,見落とされがちです。
- 実装クラスを登録する生成されたコードを変更し,実装クラスのインスタンスを作成するファクトリメソッドを含めなければなりません。
この最後のポイントには少し説明が必要です。実装クラスが TInvokableClass を継承し,継承したコンストラクタを,1 つまたは複数のパラメータを含む新しいコンストラクタで置き換えない場合,起動レジストリはクラスのインスタンスが必要になったときに作成する方法を知っています。TInvokableClass を継承しない実装クラスを作成する場合,またはコンストラクタを変更する場合は,実装クラスのインスタンスを取得する方法を起動レジストリに指示しなければなりません。
実装クラスのインスタンスを取得する方法を起動レジストリに指示するには,ファクトリ手続きを使って指定します。TInvokableClass を継承し,継承したコンストラクタを使用する実装クラスの場合でも,ファクトリ手続きを指定することができます。たとえば,起動可能インターフェースの呼び出しをアプリケーションが受信するたびに起動レジストリが新しいインスタンスを作成しなければならないのではなく,1 つのグローバルインスタンスの実装クラスを使用できます。
このファクトリ手続きは,TCreateInstanceProc 型でなければなりません。これは実装クラスのインスタンスを返します。この手続きが新しいインスタンスを作成する場合,実装オブジェクトは,インターフェースの参照カウントが 0 になったときにオブジェクト自身を解放する必要があります。なぜなら,起動レジストリはオブジェクトインスタンスを明示的に解放しないからです。次のコードは,もう 1 つの方法,つまりファクトリ手続きが 1 つのグローバルインスタンスの実装クラスを返す方法を示しています。
procedure CreateEncodeDecode(out obj: TObject);
begin
if FEncodeDecode = nil then
begin
FEncodeDecode := TEncodeDecode.Create;
{インターフェースへの参照を保存し,グローバルインスタンスが自分自身を解放しないようにする }
FEncodeDecodeInterface := FEncodeDecode as IEncodeDecode;
end;
obj := FEncodeDecode; { グローバルインスタンスを返す }
end;
void __fastcall CreateEncodeDecode(System::TObject* &obj)
{
if (!FEncodeDecode)
{
FEncodeDecode = new TEncodeDecodeImpl();
// インターフェースへの参照を保存し,グローバルインスタンスが自分自身を解放しないようにする
TEncodeDecodeImpl->QueryInterface(FEncodeDecodeInterface);
}
obj = FEncodeDecode;
}
メモ: 上の例では,FEncodeDecodeInterface は IEncodeDecode 型の変数です。
ファクトリ手続きを実装クラスに登録するには,そのクラスを起動レジストリに登録する呼び出しの 2 番めのパラメータとして指定します。まず,実装クラスを登録するためにウィザードが生成した呼び出しを探し出します。これが,クラスを定義するユニットの初期化部に表示されます。これはたとえば次のようになります。
InvRegistry.RegisterInvokableClass(TEncodeDecode);
InvRegistry()->RegisterInvokableClass(__classid(TEncodeDecodeImpl));
ファクトリ手続きを指定する 2 番めのパラメータをこの呼び出しに追加します。
InvRegistry.RegisterInvokableClass(TEncodeDecode, CreateEncodeDecode);
InvRegistry()->RegisterInvokableClass(__classid(TEncodeDecodeImpl), &CreateEncodeDecode);