Aufrufen von Dienstvorgängen und -aktionen (WCF Data Services)
Open Data Protocol (OData) definiert Dienstvorgänge und Dienstaktionen für einen Datendienst. Wie andere Datendienstressourcen werden diese Dienstvorgänge und Dienstaktionen über URIs adressiert. Dienstvorgänge und -aktionen können Auflistungen von Entitätstypen, einzelne Entitätstypinstanzen und primitive Typen wie ganze Zahl und Zeichenfolge sowie null (Nothing in Visual Basic) zurückgeben. Im Gegensatz zu Dienstvorgängen können Dienstaktionen an Datenmodellressourcen gebunden werden und müssen mit einer HTTP POST-Anforderung aufgerufen werden, da sie Nebeneffekte für das System haben. Weitere Informationen finden Sie unter Dienstvorgänge (WCF Data Services) und Verwenden von OData-Aktionen zum Implementieren des serverseitigen Verhaltens.
Dienstvorgänge und Dienstaktionen werden in den Metadaten verfügbar gemacht, die von einem Datendienst zurückgegeben werden, der OData implementiert. In den Metadaten werden beide als FunctionImport-Elemente dargestellt. Beim Generieren des stark typisierten DataServiceContext ignorieren die Tools Dienstverweis hinzufügen und DataSvcUtil.exe dieses Element. Daher finden Sie keine Methode im Kontext, die zum direkten Aufrufen eines Dienstvorgangs verwendet werden kann. Sie können Dienstvorgänge jedoch mithilfe des WCF Data Services-Clients auf eine der beiden folgenden Weisen aufrufen:
Durch Aufrufen der Execute<TElement>(Uri)-Methode für den DataServiceContext, wobei der URI des Dienstvorgangs angegeben wird. Diese Methode wird für den Aufruf aller Dienstvorgänge und -aktionen empfohlen. Rufen Sie bei Dienstaktionen oder Dienstvorgängen, die mit einer HTTP POST-Anforderung aufgerufen werden, die Execute<TElement>(Uri, String, Boolean, array<OperationParameter[])-Methodenüberladung auf, die eine httpMethod akzeptiert, und geben Sie den Wert POST an. Sie können auch während der Ausführung einen oder mehrere Parameter übergeben, indem Sie beim Aufrufen dieser Methode eine OperationParameter-Auflistung von Parameterwerten an operationParameters übergeben. Beim Aufrufen einer Dienstaktion geben Sie auf diese Weise nur Parameter ohne Bindung an.
Verwenden Sie die CreateQuery<T>(String)-Methode für den DataServiceContext, um ein DataServiceQuery<TElement>-Objekt zu erstellen. Beim Aufruf von CreateQuery<T>(String) wird der Name des Dienstvorgangs im entitySetName-Parameter angegeben. Diese Methode gibt ein DataServiceQuery<TElement>-Objekt zurück, das den Dienstvorgang bei einer Enumeration oder bei einem Aufruf der Execute()-Methode aufruft. Diese Methode wird verwendet, um GET-Dienstvorgänge aufzurufen, die eine Auflistung zurückgeben. Ein einzelner Parameter kann mit der AddQueryOption(String, Object)-Methode angegeben werden. Das von dieser Methode zurückgegebene DataServiceQuery<TElement>-Objekt kann wie jedes andere Abfrageobjekt weiter zusammengesetzt werden. Weitere Informationen finden Sie unter Abfragen des Datendiensts (WCF Data Services). Diese Methode kann nicht zum Aufrufen von Dienstaktionen verwendet werden.
Überlegungen zum Aufrufen von Dienstvorgängen und -aktionen
Die folgenden Überlegungen betreffen den Aufruf von Dienstvorgängen mithilfe des WCF Data Services-Clients.
Wenn Sie asynchron auf den Datendienst zugreifen, müssen Sie die entsprechenden asynchronen BeginExecute<TElement>(Uri, AsyncCallback, Object)-/EndExecute<TElement>(IAsyncResult)-Methoden für den DataServiceContext oder die BeginExecute(AsyncCallback, Object)-/EndExecute(IAsyncResult)-Methoden für die DataServiceQuery<TElement> verwenden.
Ziehen Sie das Erstellen einer Erweiterungsmethode in der stark typisierten DataServiceContext-Teilklasse in Betracht, die von den Tools generiert wird und entweder die CreateQuery<T>(String)-Methode oder die Execute<TElement>(Uri)-Methode zum Aufrufen eines Dienstvorgangs verwendet. Dies ermöglicht es Ihnen, Dienstvorgänge direkt aus dem Kontext heraus aufzurufen. Weitere Informationen finden Sie im Blogbeitrag Dienstvorgänge und der WCF Data Services-Client.
Wenn Sie mithilfe von CreateQuery<T>(String) einen Dienstvorgang aufrufen, versieht die Clientbibliothek automatisch an AddQueryOption(String, Object) übergebene Zeichen mit Escapezeichen, indem eine Prozentcodierung der reservierten Zeichen wie das kaufmännische Und-Zeichen (&) durchgeführt wird, sowie einfache Anführungszeichen in Zeichenfolgen. Wenn Sie jedoch eine der Execute-Methoden aufrufen, um einen Dienstvorgang aufzurufen, müssen Sie daran denken, vom Benutzer angegebene Zeichenfolgenwerte mit Escapezeichen zu versehen. Einfache Anführungszeichen in URIs werden als Paare einfacher Anführungszeichen mit Escapezeichen versehen.
Im Gegensatz zu Dienstvorgängen können Dienstaktionen nicht weiter zusammengesetzt werden. Das heißt, Sie können nach dem Aufrufen der Dienstaktion keine weiteren dienstseitigen Abfragevorgänge ausführen. Weitere Informationen finden Sie unter Verwenden von OData-Aktionen zum Implementieren des serverseitigen Verhaltens.
Beispiele für das Aufrufen von Dienstvorgängen
Dieser Abschnitt enthält die folgenden Beispiele zum Aufrufen von Dienstvorgängen mit der WCF Data Services-Clientbibliothek:
Aufrufen von Execute<T> zum Zurückgeben einer Auflistung von Entitäten
Im folgenden Beispiel wird ein Dienstvorgang mit dem Namen GetOrdersByCity aufgerufen, der den Zeichenfolgenparameter city akzeptiert und ein IQueryable<T> zurückgibt:
' 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);
}
In diesem Beispiel gibt der Dienstvorgang eine Auflistung von Order-Objekten mit zugehörigen Order_Detail-Objekten zurück.
Verwenden von CreateQuery<T> zum Zurückgeben einer Auflistung von Entitäten
Das folgende Beispiel gibt mithilfe der CreateQuery<T>(String) eine DataServiceQuery<TElement> zurück, die verwendet wird, um den gleichen GetOrdersByCity-Dienstvorgang aufzurufen:
' 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);
}
In diesem Beispiel wird die AddQueryOption(String, Object)-Methode verwendet, um der Abfrage den Parameter hinzuzufügen, und die Expand(String)-Methode wird verwendet, um zugehörige Order_Details-Objekte in die Ergebnisse einzuschließen.
Aufrufen von Execute<T> zum Zurückgeben einer einzelnen Entität
Im folgenden Beispiel wird ein Dienstvorgang mit dem Namen GetNewestOrder aufgerufen, der nur eine einzelne Order-Entität zurückgibt:
' 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);
}
In diesem Beispiel wird die FirstOrDefault<TSource>(IEnumerable<TSource>)-Methode zur Anforderung einer einzelnen Order-Entität bei der Ausführung verwendet.
Aufrufen von Execute<T> zum Zurückgeben einer Auflistung primitiver Werte
Im folgenden Beispiel wird ein Dienstvorgang aufgerufen, der eine Auflistung von Zeichenfolgenwerten zurückgibt:
' 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);
}
Aufrufen von Execute<T> zum Zurückgeben eines einzelnen primitiven Werts
Im folgenden Beispiel wird ein Dienstvorgang aufgerufen, der einen einzelnen Zeichenfolgenwert zurückgibt:
' 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);
}
In diesem Beispiel wird wieder die FirstOrDefault<TSource>(IEnumerable<TSource>)-Methode zur Anforderung eines einzelnen ganzzahligen Werts bei der Ausführung verwendet.
Aufrufen eines Dienstvorgangs, der keine Daten zurückgibt
Im folgenden Beispiel wird ein Dienstvorgang aufgerufen, der keine Daten zurückgibt:
' 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);
}
Da keine Daten zurückgegeben werden, ist der Wert der Ausführung nicht zugewiesen. Das einzige Anzeichen, dass die Anforderung erfolgreich war, besteht darin, dass keine DataServiceQueryException ausgelöst wird.
Asynchrones Aufrufen von Dienstvorgängen
Im folgenden Beispiel wird ein Dienstvorgang asynchron aufgerufen, indem BeginExecute<TElement>(Uri, AsyncCallback, Object) und EndExecute<TElement>(IAsyncResult) aufgerufen werden:
' 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);
}
}
Da keine Daten zurückgegeben werden, ist der von der Ausführung zurückgegebene Wert nicht zugewiesen. Das einzige Anzeichen, dass die Anforderung erfolgreich war, besteht darin, dass keine DataServiceQueryException ausgelöst wird.
Im folgenden Beispiel wird der gleiche Dienstvorgang asynchron mit CreateQuery<T>(String) aufgerufen:
' 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);
}
}