服務作業 (WCF Data Services)
WCF Data Services 可以讓您定義資料服務上的服務作業,以公開伺服器上的方法。 如同其他資料服務資源,服務作業依 URI 定址。 服務作業可讓您公開資料服務中的業務邏輯,例如實作驗證邏輯、套用以角色為基礎的安全性,或公開特殊的查詢功能。 服務作業是加入至從 DataService<T> 衍生之資料服務類別的方法。如同其他所有資料服務資源,您可以提供參數給服務作業方法。例如,下列服務作業 URI (以快速入門資料服務為基礎) 會將值 London 傳遞給 city 參數:
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,直接存取資料服務所使用的資料來源。 如需詳細資訊,請參閱 HOW TO:定義服務作業 (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 加上附註,以便指定此方法的傳回值是單一實體而非實體的集合。 此項差異表示 URI 中會顯示所產生的回應序列化,以及其他導覽屬性周遊的方法。 例如,使用 AtomPub 序列化時,單一資源類型執行個體會以輸入項目表示,而一組執行個體則以摘要項目表示。
定址服務作業
您可以將方法的名稱放入 URI 的第一個路徑區段中,以定址服務作業。 例如,下列 URI 會存取傳回 Orders 物件之 IQueryable<T> 集合的 GetOrdersByState 作業。
https://localhost:12345/Northwind.svc/GetOrdersByState?state='CA'&includeItems=true
呼叫服務作業時,系統會將參數當做查詢選項提供。 先前的服務作業會同時接受字串參數 state 和布林值參數 includeItems,以指出是否在回應中包含相關的 Order_Detail 物件。
以下是服務作業的有效傳回類型:
有效傳回類型 |
URI 規則 |
---|---|
void (在 Visual Basic 中為 Nothing) -或- 實體類型 -或- 基本類型 |
URI 必須是單一路徑區段,且為服務作業的名稱。 不允許使用查詢選項。 |
URI 必須是單一路徑區段,且為服務作業的名稱。 因為結果類型不是 IQueryable<T> 類型,因此不允許查詢選項。 |
|
除了為服務作業名稱的路徑外,允許查詢其他路徑區段。 亦允許使用查詢選項。 |
此外,您可以將其他路徑區段或查詢選項加入至 URI,端視服務作業的傳回類型而定。 例如,下列 URI 會存取傳回 Orders 物件之 IQueryable<T> 集合的 GetOrdersByCity 作業 (以 RequiredDate 遞減方式排序) 以及相關的 Order_Details 物件:
https://localhost:12345/Northwind.svc/GetOrdersByCity?city='London'&$expand=Order_Details&$orderby=RequiredDate desc
服務作業存取控制
服務作業的服務範圍可視性由 IDataServiceConfiguration 類別的 SetServiceOperationAccessRule 方法控制,與使用 SetEntitySetAccessRule 方法控制實體集可視性的方式非常相似。 例如,資料服務定義中的下列程式碼行可讓您存取 CustomersByCity 服務作業。
config.SetServiceOperationAccessRule( _
"GetOrdersByCity", ServiceOperationRights.AllRead)
config.SetServiceOperationAccessRule(
"GetOrdersByCity", ServiceOperationRights.AllRead);
注意
如果服務作業具有已透過現制存取基礎實體集隱藏的傳回類型,則用戶端應用程式就無法使用服務作業。
如需詳細資訊,請參閱 HOW TO:定義服務作業 (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);
}
}
}