OData アクションを使用してサーバー側の動作を実装する

Open Data Protocol (OData) では、データ サービスのサービス アクションを定義できます。 サービス アクションは、データ サービスで定義された特殊な操作です。 サービス アクションは、本来はデータ中心のモデルに動作を挿入する手段を提供します。 サービス アクションによって、ロジックを特定のリソースにバインドする必要のある OData でビジネス ロジックを呼び出すことができます。 サービス アクションが、通常のエンドポイント ベースのサービス操作と異なる点は次のとおりです。

  • リソースにバインドされる

    固定のエンドポイントで定義されるサービス操作とは異なり、サービス アクションは通常、リソース、エンティティ セット (フィード)、または個々のエンティティにバインドされます。 これらのリソースはバインド パラメーターと呼ばれます。 WCF Data Services では、バインド パラメーターとして使用できるのはエンティティ型およびエンティティ型のコレクションのみです。 サービス アクションでは、非バインド パラメーターも指定できます。 ただし、これらのパラメーターは、プリミティブ型、複合型、あるいはプリミティブ型または複合型のコレクションである必要があります。 サービス アクションがリソースにバインドされると、アクション リソースとしてサービス アクションのエンティティ シリアル化が行われます。

  • 副作用がある

    サービス アクションによって呼び出されたビジネス ロジックがシステムに影響し、データや状態が変更されたり、他のビジネス プロセスが呼び出されることがあります。 サービス アクションには常に副作用が伴うため、呼び出すことができるのは POST 要求を使用した場合だけです。 サービス操作とは異なり、非バインド パラメーターはサービス アクションの URI ではなく、メッセージ本体で指定されます。 これらの非バインド パラメーターは、JSON (JavaScript Object Notation) でエンコードされた値として要求の本体で指定されます。

  • それ以上構成できない

    サービス アクションは、サービス操作と同じ戻り値の型を持つことができます。 ただし、サービス操作とは異なり、アクションをそれ以上構成することはできません。 これは、システム クエリ オプションをサービス アクションには適用できないことを意味します。

たとえば、リソースとしてデジタル ムービーについて考えてみましょう。デジタル ムービーについては、チェックアウト、評価やコメント、チェックインなど、多様な操作が考えられます。 これらはすべて、デジタル ムービーを管理するために WCF Data Services で実装できるアクションの例です。 アクションは、そのアクションを呼び出すことのできる対象のリソースが含まれている OData 応答に記述します。 ユーザーが、デジタル ムービーを表すリソースを要求した場合、WCF Data Services から返される応答には、そのリソースに使用できるアクションに関する情報が含まれています。 アクションを使用できるかどうかは、データ サービスまたはリソースの状態によって変わる場合があります。 たとえば、デジタル ムービーがチェックアウトされている場合、それを別のユーザーがチェックアウトすることはできません。 クライアントは、URL を指定するだけでアクションを呼び出すことができます。 たとえば、「http://MyServer/MovieService.svc/Movies(6)」と指定すると特定のデジタル ムービーが示され、「http://MyServer/MovieService.svc/Movies(6)/Checkout」と指定すると特定のムービーに対するアクションが呼び出されます。 アクションを使用すると、データ モデルを公開することなくサービス モデルを公開することができます。 先ほどのムービー サービスを例とすると、評価データをリソースとして直接公開せずにムービーをユーザーが評価できるようにするというケースが考えられます。 そこで、たとえば Rate (評価) アクションを実装することにより、リソースとして評価データに直接アクセスせずに、ムービーをユーザーが評価できるようにすることができます。

アクションの実装

サービス アクションを実装するには、IServiceProvider インターフェイス、IDataServiceActionProvider インターフェイス、および IDataServiceInvokable インターフェイスを実装する必要があります。 IServiceProvider を使用すると WCF Data Services は、IDataServiceActionProvider の実装を取得できます。 IDataServiceActionProvider を使用すると WCF Data Services は、サービス アクションの作成、検出、記述、および呼び出しを行うことができます。 IDataServiceInvokable を使用すると、サービス アクションの動作を実装して結果 (ある場合) を取得するコードを呼び出すことができます。 WCF Data Services は呼び出しごとの WCF サービスであり、サービスの新しいインスタンスは、サービスが呼び出されるごとに作成されます。 サービスの作成時に、不要な作業が行われないよう注意してください。

IServiceProvider

IServiceProvider には、GetService(Type) というメソッドが含まれています。 このメソッドは、メタデータ サービス プロバイダーやデータ サービス アクション プロバイダーなど、いくつかのサービス プロバイダーを取得するために、WCF Data Services によって呼び出されます。 データ サービス アクション プロバイダーを求められた場合は、IDataServiceActionProvider 実装を返します。

IDataServiceActionProvider

IDataServiceActionProvider には、使用可能なアクションに関する情報を取得するためのメソッドが含まれています。 IDataServiceActionProvider を実装すると、サービスの IDataServiceMetadataProvider 実装で定義されるサービスのメタデータにアクションが追加され、必要に応じてアクションへのディスパッチが処理されます。

AdvertiseServiceAction

AdvertiseServiceAction(DataServiceOperationContext, ServiceAction, Object, Boolean, ODataAction%) は、指定されたリソースに対して使用できるアクションを判断するために呼び出されます。 このメソッドは、常時使用可能ではないアクションについてのみ呼び出されます。 このメソッドの用途は、要求されているリソースの状態またはサービスの状態に基づいて、アクションを OData 応答に含めるかどうかを確認することです。 この確認をどのように行うかは、開発者が指定する必要があります。 使用可能かどうかを計算する処理の負荷が高く、現在のリソースがフィード内にある場合は、確認をスキップしてアクションの情報提供を行うこともできます。 返される現在のリソースがフィードの一部である場合は、inFeed パラメーターが true に設定されます。

CreateInvokable

CreateInvokable(DataServiceOperationContext, ServiceAction, array<Object[]) は、アクションの動作が実装されたコードをカプセル化するデリゲートが含まれた IDataServiceInvokable を作成する場合に呼び出します。 これにより IDataServiceInvokable インスタンスが作成されますが、アクションの呼び出しは行われません。 WCF Data Services のアクションは副作用を伴うため、更新プロバイダーと連携して、その変更をディスクに保存する必要があります。 Invoke() メソッドは、更新プロバイダーの SaveChanges() メソッドが呼び出された後に呼び出されます。

GetServiceActions

このメソッドは、WCF Data Services が公開するすべてのアクションを表す ServiceAction インスタンスのコレクションを返します。 ServiceAction は、アクションのメタデータ表現であり、アクションの名前、パラメーター、戻り値の型などの情報を含んでいます。

GetServiceActionsByBindingParameterType

このメソッドは、指定されたバインディング パラメーターの種類にバインドできるすべての ServiceAction インスタンスのコレクションを返します。 つまり、指定されたリソースの種類 (バインディング パラメーターの種類) を操作できるすべての ServiceAction を表します。サービスがリソースを返すときに、そのリソースに対して呼び出すことのできるアクションの情報を含めるために使用します。 このメソッドが返すアクションは、(派生型ではなく) 指定どおりのバインディング パラメーターの種類にバインドできるアクションのみです。 このメソッドは、要求ごと、検出された種類ごとに 1 回呼び出され、結果は WCF Data Services によってキャッシュされます。

TryResolveServiceAction

このメソッドは、指定された ServiceAction を検索し、ServiceAction が見つかった場合は true を返します。 見つかった場合、out パラメーター serviceAction で ServiceAction が返されます。

IDataServiceInvokable

このインターフェイスは、WCF Data Services アクションの実行方法を提供します。 IDataServiceInvokable を実装する場合は、次の 3 つを行う必要があります。

  1. パラメーターをキャプチャし、場合によってはマーシャリングを行う。

  2. Invoke() の呼び出し時に、アクションを実際に実装するコードにパラメーターをディスパッチする。

  3. GetResult() を使用して取得できるように、Invoke() の結果を保存する。

パラメーターは、トークンとして渡すことができます。 これは、リソースを表すトークンを扱うデータ サービス プロバイダーを作成することができるためです。ただしその場合は、実際のアクションにディスパッチする前に、トークンを実際のリソースに変換 (マーシャリング) する必要があります。 アクションが呼び出されたときに発生したリソースへの変更を保存してディスクに書き込むことができるよう、マーシャリングを行ったパラメーターは編集可能な状態にしておく必要があります。

このインターフェイスには、Invoke および GetResult という 2 つのメソッドが必要です。 Invoke はアクションの動作を実装するデリゲートを呼び出し、GetResult はアクションの結果を返します。

サービス アクションのアクセス制御

WCF Data Services では、サービス アクションのサービス全体の表示は、IDataServiceConfiguration クラスの SetServiceActionAccessRule(String, ServiceActionRights) メソッドによって制御されます。この方法は、サービス操作の表示が SetServiceOperationAccessRule(String, ServiceOperationRights) メソッドを使用して制御される場合と同じです。

サービス アクションのメタデータの定義

サービス操作と同様に、サービス アクションはサービス メタデータの FunctionImport 要素として定義されます。 FunctionImport サービス アクションには、バインド パラメーターと非バインド パラメーターの両方を表す 0 個以上の Parameter 要素が含まれています。 さらに、FunctionImport の次の属性がサービス アクションの動作を定義します。

  • IsSideEffecting

    サービス アクションには常に副作用が伴うため、この属性は常に true です。

  • IsBindable

    サービス アクションは通常、リソースにバインドされますが、常にバインドされるわけではありません。 この属性が true の場合、最初のパラメーターはエンティティ型またはエンティティ コレクションである必要があります。

  • IsComposable

    サービス アクションでは追加のクエリ構成がサポートされないため、この属性は常に false です。

WCF Data Services アクションの呼び出し

アクションは HTTP POST 要求を使用して呼び出します。 リソースの後にアクション名を続けて URL を指定します。 パラメーターは、要求の本文を使用して渡します。 たとえば、MovieService というサービスがあり、Rate というアクションが公開されているとします。 この場合、特定のムービーに対して Rate アクションを呼び出すには、次のような URL 使用することができます。

http://MovieServer/MovieService.svc/Movies(1)/Rate

Movies(1) は評価対象のムービーを示し、Rate は Rate アクションを指定しています。 次の例に示すように、評価の実際の値は HTTP 要求の本文に含まれます。

POST http://MovieServer/MoviesService.svc/Movies(1)/Rate HTTP/1.1 
Content-Type: application/json 
Content-Length: 20 
Host: localhost:15238
{ 
   "rating": 4 
}

注意

上のサンプル コードが動作するのは、JSON Light をサポートする WCF Data Services 5.2 以降を使用している場合のみです。それより前のバージョンの WCF Data Services を使用している場合は、Verbose JSON の Content-Type を「application/json;odata=verbose」のように指定する必要があります。

また、次のコード スニペットのように、WCF Data Services クライアントを使用してアクションを呼び出すこともできます。

MoviesModel context = new MoviesModel (new Uri("http://MyServer/MoviesService.svc/"));
            //...
            context.Execute(new Uri("http://MyServer/MoviesService.svc/Movies(1)/Rate"), "POST", new BodyOperationParameter("rating",4) );         

上のコード スニペットの MoviesModel クラスは、Visual Studio の [サービス参照の追加] で WCF Data Services への参照を追加することでが生成されたものです。

関連項目

概念

WCF Data Services の開発と配置

カスタム データ サービス プロバイダー (WCF Data Services)

その他の技術情報

WCF Data Services

データ サービス (WCF Data Services)