WCF Data Services では、データ サービスでサービス操作を定義して、サーバーでメソッドを公開できます。 その他のデータ サービス リソースと同様に、サービス操作は URI によってアドレス指定できます。 サービス操作では、データ サービスでビジネス ロジックを公開できます (検証ロジックの実装、ロール ベースのセキュリティの適用、特殊なクエリ機能の公開など)。 サービス操作は、DataService<T> から派生したデータ サービス クラスに追加されたメソッドです。他のすべてのデータ サービス リソースのように、サービス操作メソッドにパラメーターを指定できます。たとえば、次のサービス操作 URIでは、クイック スタート データ サービスに基づいて、city パラメーターに値 London を渡します。
https://localhost:12345/Northwind.svc/GetOrdersByCity?city='London'
このサービス操作の定義を次に示します。
<WebGet()> _
Public Function GetOrdersByCity(ByVal city As String) As IQueryable(Of Order)
[WebGet]
public IQueryable<Order> GetOrdersByCity(string city)
DataService<T> の CurrentDataSource を使用して、データ サービスが使用するデータ ソースに直接アクセスできます。 詳細については、「方法: サービス操作を定義する (WCF Data Services)」を参照してください。
.NET Framework クライアント アプリケーションからサービス操作を呼び出す方法の詳細については、「サービス操作およびサービス アクションの呼び出し (WCF Data Services)」を参照してください。
サービス操作の要件
データ サービスでサービス操作を定義する場合、次の要件が適用されます。 これらの要件を満たしていないメソッドは、データ サービスのサービス操作として公開されません。
操作は、データ サービス クラスのメンバーであるパブリック インスタンス メソッドである必要があります。
操作メソッドは入力パラメーターだけを受け取ることができます。 メッセージの本文内で送信されるデータは、データ サービスからアクセスできません。
パラメーターを定義する場合、各パラメーターの型はプリミティブ型である必要があります。 非プリミティブ型のいずれかのデータもシリアル化され、文字列パラメーターに渡される必要があります。
メソッドは次のいずれかを返す必要があります。
void (Visual Basic では Nothing)。
データ サービスが公開するデータ モデル内のエンティティ型。
プリミティブ クラス (整数や文字列など)。
並べ替え、ページング、フィルター処理などのクエリ オプションをサポートするために、サービス操作メソッドから IQueryable<T> が返される必要があります。 クエリ オプションを含むサービス操作への要求は、IEnumerable<T> だけを返す操作で拒否されます。
ナビゲーション プロパティを使用した関連エンティティへのアクセスをサポートするために、サービス操作は IQueryable<T> を返す必要があります。
メソッドには、[WebGet] 属性または [WebInvoke] 属性を使用して注釈を付ける必要があります。
[WebGet] では、GET 要求を使用してメソッドを呼び出すことができます。
[WebInvoke(Method = "POST")] では、POST 要求を使用してメソッドを呼び出すことができます。 その他の WebInvokeAttribute メソッドはサポートされていません。
サービス操作には、SingleResultAttribute を使用して注釈を付けることができます。この属性は、メソッドからの戻り値がエンティティのコレクションではなく 1 つのエンティティとなるように指定します。 この区別により、応答の結果のシリアル化、および追加のナビゲーション プロパティのトラバーサルを URI で表す方法が決定されます。 たとえば、AtomPub シリアル化を使用すると、1 種類のリソースのインスタンスがエントリ要素として表され、一連のインスタンスがフィード要素として表されます。
サービス操作のアドレス指定
メソッドの名前を URI の最初のパス セグメントに配置することによってサービス操作のアドレスを指定できます。 たとえば、次の URI の場合、Orders オブジェクトの IQueryable<T> コレクションを返す GetOrdersByState 操作にアクセスします。
https://localhost:12345/Northwind.svc/GetOrdersByState?state='CA'&includeItems=true
サービス操作を呼び出すときは、パラメーターはクエリのオプションとして指定されます。 前のサービス操作は、文字列パラメーター state と、関連する Order_Detail オブジェクトを応答に含めるかどうかを指定するブール値パラメーター includeItems の両方を受け入れます。
サービス操作の有効な戻り値の型を次に示します。
有効な戻り値の型 |
URI のルール |
|---|---|
void (Visual Basic では Nothing)。 または エンティティ型 または プリミティブ型 |
URI は、サービス操作の名前である 1 つのパス セグメントである必要があります。 クエリ オプションは許可されません。 |
URI は、サービス操作の名前である 1 つのパス セグメントである必要があります。 結果型は IQueryable<T> 型ではないので、クエリ オプションは使用できません。 |
|
サービス操作の名前であるパスに追加したクエリ パス セグメント セグメントが許可されます。 クエリ オプションも許可されます。 |
サービス操作の戻り値の型によっては、パス セグメントやクエリ オプションをさらに URI に追加できます。 たとえば、次の URI は、関連する Order_Details オブジェクトと一緒に Orders オブジェクトの IQueryable<T> コレクションを RequiredDate の降順で返す GetOrdersByCity 操作にアクセスします。
https://localhost:12345/Northwind.svc/GetOrdersByCity?city='London'&$expand=Order_Details&$orderby=RequiredDate desc
サービス操作のアクセス制御
サービス操作のサービス全体の表示は、エンティティ セットの表示が SetEntitySetAccessRule メソッドを使用して制御されるのと同じような方法で、IDataServiceConfiguration クラスの SetServiceOperationAccessRule メソッドによって制御されます。 たとえば、データ サービス定義内の次のコード行は、CustomersByCity サービス操作へのアクセスを有効にします。
config.SetServiceOperationAccessRule( _
"GetOrdersByCity", ServiceOperationRights.AllRead)
config.SetServiceOperationAccessRule(
"GetOrdersByCity", ServiceOperationRights.AllRead);
注意
元になるエンティティ セットの制限アクセスによって非表示にされている戻り値の型がサービス操作にある場合、サービス操作はクライアント アプリケーションで使用できません。
詳細については、「方法: サービス操作を定義する (WCF Data Services)」を参照してください。
例外の発生
データ サービスの実行で例外が発生するたびに、DataServiceException クラスを使用することお勧めします。 これは、データ サービス ランタイムがこの例外のオブジェクトのプロパティを HTTP 応答メッセージに正しくマップする方法を認識しているためです。 サービス操作で DataServiceException が発生する場合、返された例外は TargetInvocationException にラップされています。 TargetInvocationException をラップせずにベース DataServiceException を返すには、DataService<T> の HandleException(HandleExceptionArgs) メソッドをオーバーライドし、TargetInvocationException から DataServiceException を抽出して、トップ レベル エラーとして返す必要があります。次に例を示します。
' Override to manage returned exceptions.
Protected Overrides Sub HandleException(args As HandleExceptionArgs)
' Handle exceptions raised in service operations.
If args.Exception.GetType() = GetType(TargetInvocationException) _
AndAlso args.Exception.InnerException IsNot Nothing Then
If args.Exception.InnerException.GetType() = GetType(DataServiceException) Then
' Unpack the DataServiceException.
args.Exception = _
TryCast(args.Exception.InnerException, DataServiceException)
Else
' Return a new DataServiceException as "400: bad request."
args.Exception = _
New DataServiceException(400, args.Exception.InnerException.Message)
End If
End If
End Sub
// Override to manage returned exceptions.
protected override void HandleException(HandleExceptionArgs args)
{
// Handle exceptions raised in service operations.
if (args.Exception.GetType() ==
typeof(TargetInvocationException)
&& args.Exception.InnerException != null)
{
if (args.Exception.InnerException.GetType()
== typeof(DataServiceException))
{
// Unpack the DataServiceException.
args.Exception = args.Exception.InnerException as DataServiceException;
}
else
{
// Return a new DataServiceException as "400: bad request."
args.Exception =
new DataServiceException(400,
args.Exception.InnerException.Message);
}
}
}