呼叫服務作業和動作 (WCF Data Services)
Open Data Protocol (OData) 會針對資料服務定義服務作業和服務動作。 就像其他資料服務資源,服務作業和服務動作會使用 URI 來定址。 服務作業和動作都可以傳回實體類型集合、單一實體類型執行個體、基本類型 (例如整數和字串) 以及 null (Visual Basic 中為 Nothing)。 與服務作業不同的是,服務動作可以繫結至資料模型資源而且必須使用 HTTP POST 要求來呼叫,因為服務動作對系統有副作用。 如需詳細資訊,請參閱服務作業 (WCF Data Services) 和使用 OData 動作實作伺服器端行為。
服務作業和服務動作都會在實作 OData 之資料服務所傳回的中繼資料中公開。 在中繼資料中,兩者都會表示為 FunctionImport 元素。 產生強型別 DataServiceContext 時,[加入服務參考] 和 DataSvcUtil.exe 工具會忽略此元素。 因此,您在內容上找不到可用來直接呼叫服務作業的方法。 但是,您仍然可以使用 WCF Data Services 用戶端,透過下列兩種方式呼叫服務作業:
在 DataServiceContext 上呼叫 Execute<TElement>(Uri) 方法,以提供服務作業的 URI。 建議使用這個方法來呼叫所有服務作業和服務動作。 如果是使用 HTTP POST 要求所呼叫的服務動作或服務作業,請呼叫採用 httpMethod 的 Execute<TElement>(Uri, String, Boolean, array<OperationParameter[]) 方法多載,並提供 POST 值。 您也可以在呼叫這個方法時,將參數值的 OperationParameter 集合傳遞給 operationParameters,於執行期間提供一個或多個參數。 當您呼叫服務動作時,您只能以這種方式提供非繫結參數。
在 DataServiceContext 上使用 CreateQuery<T>(String) 方法,以建立 DataServiceQuery<TElement> 物件。 呼叫 CreateQuery<T>(String) 時,要將服務作業的名稱提供給 entitySetName 參數。 列舉時或呼叫 Execute() 方法時,此方法會傳回呼叫服務作業的 DataServiceQuery<TElement> 物件。 此方法用於呼叫傳回集合的 GET 服務作業。 可以使用 AddQueryOption(String, Object) 方法提供單一參數。 此方法傳回的 DataServiceQuery<TElement> 物件就像任何查詢物件一樣,可以進一步加以撰寫。 如需詳細資訊,請參閱查詢資料服務 (WCF Data Services)。 此方法無法用來呼叫服務動作。
呼叫服務作業和動作的考量
使用 WCF Data Services 用戶端呼叫服務作業時,適用下列考量。
以非同步方式存取資料服務時,您必須使用 DataServiceContext 上的同等非同步 BeginExecute<TElement>(Uri, AsyncCallback, Object)/ EndExecute<TElement>(IAsyncResult) 方法,或是 DataServiceQuery<TElement> 上的 BeginExecute(AsyncCallback, Object)/ EndExecute(IAsyncResult) 方法。
如果在工具產生的強型別 DataServiceContext 部分類別上建立擴充方法,這個方法使用 CreateQuery<T>(String) 或 Execute<TElement>(Uri) 方法來呼叫服務作業。 這可讓您直接從內容中呼叫服務作業。 如需詳細資訊,請參閱部落格文章服務作業和 WCF Data Services 用戶端。
當您使用 CreateQuery<T>(String) 呼叫服務作業時,用戶端程式庫會自動執行保留字元 (例如字串中的 & 符號和單引號逸出) 的百分比編碼,以逸出提供給 AddQueryOption(String, Object) 的字元。 但是,當您呼叫其中一個 Execute 方法來呼叫服務作業時,請務必記得對使用者提供的任何字串值執行這項逸出。 URI 中的單引號是以一對單引號的形式來逸出。
與服務作業不同的是,服務動作將無法進一步組成。 這表示您在呼叫服務動作之後,將無法執行任何其他的服務端查詢作業。 如需詳細資訊,請參閱使用 OData 動作實作伺服器端行為。
呼叫服務作業的範例
本節包含下列範例,說明如何使用 WCF Data Services 用戶端程式庫呼叫服務作業:
呼叫 Execute<T> 以傳回實體集合
下列範例會呼叫名為 GetOrdersByCity 的服務作業,這項作業接受字串參數 city 並傳回 IQueryable<T>:
' Define the service operation query parameter.
Dim city As String = "London"
' Define the query URI to access the service operation with specific
' query options relative to the service URI.
Dim queryString As String = String.Format("GetOrdersByCity?city='{0}'", city) _
& "&$orderby=ShippedDate desc" _
& "&$expand=Order_Details"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
Try
' Execute the service operation that returns all orders for the specified city.
Dim results = context.Execute(Of Order)(New Uri(queryString, UriKind.Relative))
' Write out order information.
For Each o As Order In results
Console.WriteLine(String.Format("Order ID: {0}", o.OrderID))
For Each item As Order_Detail In o.Order_Details
Console.WriteLine(String.Format(vbTab & "Item: {0}, quantity: {1}", _
item.ProductID, item.Quantity))
Next
Next
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the service operation query parameter.
string city = "London";
// Define the query URI to access the service operation with specific
// query options relative to the service URI.
string queryString = string.Format("GetOrdersByCity?city='{0}'", city)
+ "&$orderby=ShippedDate desc"
+ "&$expand=Order_Details";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
try
{
// Execute the service operation that returns all orders for the specified city.
var results = context.Execute<Order>(new Uri(queryString, UriKind.Relative));
// Write out order information.
foreach (Order o in results)
{
Console.WriteLine(string.Format("Order ID: {0}", o.OrderID));
foreach (Order_Detail item in o.Order_Details)
{
Console.WriteLine(String.Format("\tItem: {0}, quantity: {1}",
item.ProductID, item.Quantity));
}
}
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
在此範例中,服務作業會傳回 Order 物件集合與相關的 Order_Detail 物件。
使用 CreateQuery<T> 以傳回實體集合
下列範例會使用 CreateQuery<T>(String) 傳回用來呼叫相同 GetOrdersByCity 服務作業的 DataServiceQuery<TElement>:
' Define the service operation query parameter.
Dim city As String = "London"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
' Use the CreateQuery method to create a query that accessess
' the service operation passing a single parameter.
Dim query = context.CreateQuery(Of Order)("GetOrdersByCity") _
.AddQueryOption("city", String.Format("'{0}'", city)).Expand("Order_Details")
Try
' The query is executed during enumeration.
For Each o As Order In query
Console.WriteLine(String.Format("Order ID: {0}", o.OrderID))
For Each item As Order_Detail In o.Order_Details
Console.WriteLine(String.Format(vbTab & "Item: {0}, quantity: {1}", _
item.ProductID, item.Quantity))
Next
Next
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the service operation query parameter.
string city = "London";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
// Use the CreateQuery method to create a query that accessess
// the service operation passing a single parameter.
var query = context.CreateQuery<Order>("GetOrdersByCity")
.AddQueryOption("city", string.Format("'{0}'", city))
.Expand("Order_Details");
try
{
// The query is executed during enumeration.
foreach (Order o in query)
{
Console.WriteLine(string.Format("Order ID: {0}", o.OrderID));
foreach (Order_Detail item in o.Order_Details)
{
Console.WriteLine(String.Format("\tItem: {0}, quantity: {1}",
item.ProductID, item.Quantity));
}
}
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
在此範例中,AddQueryOption(String, Object) 方法用於將參數加入至查詢中,而 Expand(String) 方法則用於將相關的 Order_Details 物件包含在結果中。
呼叫 Execute<T> 以傳回單一實體
下列範例會呼叫名為 GetNewestOrder 的服務作業,這項作業只傳回單一 Order 實體:
' Define the query URI to access the service operation,
' relative to the service URI.
Dim queryString As String = "GetNewestOrder"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
Try
' Execute a service operation that returns only the newest single order.
Dim o As Order = _
context.Execute(Of Order)( _
New Uri(queryString, UriKind.Relative)).FirstOrDefault()
' Write out order information.
Console.WriteLine(String.Format("Order ID: {0}", o.OrderID))
Console.WriteLine(String.Format("Order date: {0}", o.OrderDate))
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the query URI to access the service operation,
// relative to the service URI.
string queryString = "GetNewestOrder";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
try
{
// Execute a service operation that returns only the newest single order.
Order order
= (context.Execute<Order>(new Uri(queryString, UriKind.Relative)))
.FirstOrDefault();
// Write out order information.
Console.WriteLine(string.Format("Order ID: {0}", order.OrderID));
Console.WriteLine(string.Format("Order date: {0}", order.OrderDate));
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
此範例會使用 FirstOrDefault<TSource>(IEnumerable<TSource>) 方法,在執行時只要求單一 Order 實體。
呼叫 Execute<T> 以傳回基本值集合
下列範例會呼叫傳回字串值集合的服務作業:
' Define the query URI to access the service operation,
' relative to the service URI.
Dim queryString As String = "GetCustomerNames"
'Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
Try
' Execute a service operation that returns a collection of customer names.
Dim customerNames As IEnumerable(Of String) _
= context.Execute(Of String)(New Uri(queryString, UriKind.Relative))
For Each name As String In customerNames
' Write out customer information.
Console.WriteLine(name)
Next
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the query URI to access the service operation,
// relative to the service URI.
string queryString = "GetCustomerNames";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
try
{
// Execute a service operation that returns a collection of customer names
IEnumerable<string> customerNames
= context.Execute<string>(new Uri(queryString, UriKind.Relative));
foreach (string name in customerNames)
{
// Write out customer information.
Console.WriteLine(name);
}
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
呼叫 Execute<T> 以傳回單一基本值
下列範例會呼叫傳回單一字串值的服務作業:
' Define the query URI to access the service operation,
' relative to the service URI.
Dim queryString As String = "CountOpenOrders"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
Try
' Execute a service operation that returns the integer
' count of open orders.
Dim numOrders As Integer = context.Execute(Of Integer)( _
New Uri(queryString, UriKind.Relative)).FirstOrDefault()
' Write out the number of open orders.
Console.WriteLine(String.Format("Open orders as of {0}: {1}",
DateTime.Today.Date, numOrders))
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the query URI to access the service operation,
// relative to the service URI.
string queryString = "CountOpenOrders";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
try
{
// Execute a service operation that returns the integer
// count of open orders.
int numOrders
= (context.Execute<int>(new Uri(queryString, UriKind.Relative)))
.FirstOrDefault();
// Write out the number of open orders.
Console.WriteLine(string.Format("Open orders as of {0}: {1}",
DateTime.Today.Date, numOrders));
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
此範例又一次使用 FirstOrDefault<TSource>(IEnumerable<TSource>) 方法,在執行時只要求單一整數值。
呼叫不傳回任何資料的服務作業
下列範例會呼叫不傳回任何資料的服務作業:
' Define the query URI to access the service operation,
' relative to the service URI.
Dim queryString As String = "ReturnsNoData"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
Try
' Execute a service operation that returns void.
context.Execute(Of String)( _
New Uri(queryString, UriKind.Relative))
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
// Define the query URI to access the service operation,
// relative to the service URI.
string queryString = "ReturnsNoData";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
try
{
// Execute a service operation that returns void.
context.Execute<string>(new Uri(queryString, UriKind.Relative));
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
由於不傳回資料,因此沒有指派執行的值。 指出要求已成功的唯一表示就是沒有引發 DataServiceQueryException。
非同步呼叫服務作業
下列範例會藉由呼叫 BeginExecute<TElement>(Uri, AsyncCallback, Object) 和 EndExecute<TElement>(IAsyncResult),非同步呼叫服務作業:
' Define the service operation query parameter.
Dim city As String = "London"
' Define the query URI to access the service operation with specific
' query options relative to the service URI.
Dim queryString As String = String.Format("GetOrdersByCity?city='{0}'", city) _
& "&$orderby=ShippedDate desc" _
& "&$expand=Order_Details"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
' Define the delegate to callback into the process
Dim callback As AsyncCallback = AddressOf OnAsyncExecutionComplete
' Execute the service operation that returns
' all orders for the specified city.
Dim results = context.BeginExecute(Of Order)( _
New Uri(queryString, UriKind.Relative), _
callback, context)
// Define the service operation query parameter.
string city = "London";
// Define the query URI to access the service operation with specific
// query options relative to the service URI.
string queryString = string.Format("GetOrdersByCity?city='{0}'", city)
+ "&$orderby=ShippedDate desc"
+ "&$expand=Order_Details";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
// Execute the service operation that returns
// all orders for the specified city.
var results = context.BeginExecute<Order>(
new Uri(queryString, UriKind.Relative),
OnAsyncExecutionComplete, context);
Private Shared Sub OnAsyncExecutionComplete(ByVal result As IAsyncResult)
' Get the context back from the stored state.
Dim context = TryCast(result.AsyncState, NorthwindEntities)
Try
' Complete the exection and write out the results.
For Each o As Order In context.EndExecute(Of Order)(result)
Console.WriteLine(String.Format("Order ID: {0}", o.OrderID))
For Each item As Order_Detail In o.Order_Details
Console.WriteLine(String.Format(vbTab & "Item: {0}, quantity: {1}", _
item.ProductID, item.Quantity))
Next
Next
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
End Sub
private static void OnAsyncExecutionComplete(IAsyncResult result)
{
// Get the context back from the stored state.
var context = result.AsyncState as NorthwindEntities;
try
{
// Complete the exection and write out the results.
foreach (Order o in context.EndExecute<Order>(result))
{
Console.WriteLine(string.Format("Order ID: {0}", o.OrderID));
foreach (Order_Detail item in o.Order_Details)
{
Console.WriteLine(String.Format("\tItem: {0}, quantity: {1}",
item.ProductID, item.Quantity));
}
}
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
}
由於不傳回資料,因此沒有指派執行傳回的值。 指出要求已成功的唯一表示就是沒有引發 DataServiceQueryException。
下列範例會使用 CreateQuery<T>(String),非同步呼叫相同的服務作業:
' Define the service operation query parameter.
Dim city As String = "London"
' Create the DataServiceContext using the service URI.
Dim context As NorthwindEntities = New NorthwindEntities(svcUri2)
' Use the CreateQuery method to create a query that accessess
' the service operation passing a single parameter.
Dim query = context.CreateQuery(Of Order)("GetOrdersByCity") _
.AddQueryOption("city", String.Format("'{0}'", city)) _
.Expand("Order_Details")
' Define the delegate to callback into the process
Dim callback As AsyncCallback = AddressOf OnAsyncQueryExecutionComplete
' Execute the service operation that returns
' all orders for the specified city.
Dim results = _
query.BeginExecute(callback, query)
// Define the service operation query parameter.
string city = "London";
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri2);
// Use the CreateQuery method to create a query that accessess
// the service operation passing a single parameter.
var query = context.CreateQuery<Order>("GetOrdersByCity")
.AddQueryOption("city", string.Format("'{0}'", city))
.Expand("Order_Details");
// Execute the service operation that returns
// all orders for the specified city.
var results =
query.BeginExecute(OnAsyncQueryExecutionComplete, query);
Private Shared Sub OnAsyncQueryExecutionComplete(ByVal result As IAsyncResult)
' Get the query back from the stored state.
Dim query = TryCast(result.AsyncState, DataServiceQuery(Of Order))
Try
' Complete the exection and write out the results.
For Each o As Order In query.EndExecute(result)
Console.WriteLine(String.Format("Order ID: {0}", o.OrderID))
For Each item As Order_Detail In o.Order_Details
Console.WriteLine(String.Format(vbTab & "Item: {0}, quantity: {1}", _
item.ProductID, item.Quantity))
Next
Next
Catch ex As DataServiceQueryException
Dim response As QueryOperationResponse = ex.Response
Console.WriteLine(response.Error.Message)
End Try
End Sub
private static void OnAsyncQueryExecutionComplete(IAsyncResult result)
{
// Get the query back from the stored state.
var query = result.AsyncState as DataServiceQuery<Order>;
try
{
// Complete the exection and write out the results.
foreach (Order o in query.EndExecute(result))
{
Console.WriteLine(string.Format("Order ID: {0}", o.OrderID));
foreach (Order_Detail item in o.Order_Details)
{
Console.WriteLine(String.Format("\tItem: {0}, quantity: {1}",
item.ProductID, item.Quantity));
}
}
}
catch (DataServiceQueryException ex)
{
QueryOperationResponse response = ex.Response;
Console.WriteLine(response.Error.Message);
}
}