Appel des actions et opérations de service (WCF Data Services)
Protocole OData (Open Data) définit les opérations et actions de service d'un service de données. Comme les autres ressources du service de données, ces opérations et actions de service sont traitées via les URI. Les opérations et actions de service peuvent retourner des collections de types d'entité, des instances uniques de type d'entité, des types primitifs, comme des entiers et des chaînes, et des valeurs null (Nothing en Visual Basic). Contrairement aux opérations de service, les actions de service actions peuvent être liées à des ressources de modèle de données et doivent être appelées à l'aide d'une requête HTTP POST car elles entraînent des effets secondaires sur le système. Pour plus d'informations, consultez Opérations de service (WCF Data Services) et Utilisation des actions OData pour implémenter le comportement côté serveur.
Les opérations et actions de service sont exposées dans les métadonnées retournées par un service de données qui implémente OData. Dans les métadonnées, elles sont représentées sous la forme d'éléments FunctionImport. Lors de la génération du DataServiceContextfortement typé, les outils Ajouter une référence de service et DataSvcUtil.exe ignorent cet élément. De ce fait, vous ne trouverez pas de méthode dans le contexte pouvant être utilisée pour appeler une opération de service directement. Toutefois, vous pouvez encore utiliser le client Services de données WCF pour appeler les opérations de service de l'une des deux façons suivantes :
En appelant la méthode Execute<TElement>(Uri) sur DataServiceContext et en fournissant l'URI de l'opération de service. Cette méthode est recommandée pour appeler toutes les opérations et actions de service. Pour les actions et opérations de service appelées à l'aide d'une requête HTTP POST, appelez la surcharge de la méthode Execute<TElement>(Uri, String, Boolean, array<OperationParameter[]) qui accepte un paramètre httpMethod, et précisez la valeur POST. Vous pouvez également renseigner un ou plusieurs paramètres lors de l'exécution en transmettant une collections de valeurs de paramètres OperationParameter à operationParameters lors de l'appel de cette méthode. En appelant une action de service, vous ne pouvez fournir que des paramètres non liants.
À l'aide de la méthode CreateQuery<T>(String) sur DataServiceContext pour créer un objet DataServiceQuery<TElement>. En appelant CreateQuery<T>(String), le nom de l'opération de service est fourni au paramètre entitySetName. Cette méthode retourne un objet DataServiceQuery<TElement> qui appelle l'opération de service si elle est énumérée ou lorsque la méthode Execute() est appelée. Cette méthode est utilisée pour appeler les opérations de service GET qui retournent une collection. Un seul paramètre peut être fourni à l'aide de la méthode AddQueryOption(String, Object). L'objet DataServiceQuery<TElement> retourné par cette méthode peut être davantage composé comme n'importe quel objet de requête. Pour plus d'informations, consultez Interrogation du service de données (WCF Data Services). Cette méthode ne peut pas être utilisée pour appeler des actions de service.
Considérations sur l'appel des opérations et actions de service
Les considérations suivantes s'appliquent lorsque vous utilisez le client Services de données WCF pour appeler des opérations de service.
Lors de l'accès au service de données de façon asynchrone, vous devez utiliser les équivalents asynchrones BeginExecute<TElement>(Uri, AsyncCallback, Object)/EndExecute<TElement>(IAsyncResult) DataServiceContext ou les méthodes BeginExecute(AsyncCallback, Object)/EndExecute(IAsyncResult) sur DataServiceQuery<TElement>.
Envisagez de créer une méthode d'extension pour la classe partielle fortement typée DataServiceContext, générée par les outils, qui utilise la méthode CreateQuery<T>(String) ou Execute<TElement>(Uri) pour appeler une opération de service. Cela vous permet d'appeler les opérations de service directement à partir du contexte. Pour plus d'informations, consultez la publication de blog Opérations de service et client WCF Data Services.
Lorsque vous utilisez CreateQuery<T>(String) pour appeler une opération de service, les caractères de la bibliothèque cliente fournis au AddQueryOption(String, Object) font automatiquement l'objet d'une séquence d'échappement via l'exécution d'encodage de pourcentage des caractères réservés, tels que l'esperluette ((&), et l'échappement des guillemets simples dans les chaînes. Toutefois, lorsque vous appelez l'une des méthodes Execute pour appeler une opération de service, n'oubliez pas d'effectuer cet échappement pour toutes les valeurs de type chaîne fournies par l'utilisateur. Les guillemets simples des URI sont placés dans une séquence d'échappement comme guillemets doubles.
Contrairement aux opérations de service, les actions de service ne peuvent pas être composées davantage. Cela signifie que vous ne pouvez pas effectuer d'opérations de requête supplémentaires côté service après avoir appelé l'action de service. Pour plus d'informations, consultez Utilisation des actions OData pour implémenter le comportement côté serveur.
Exemples d'appel d'opérations de service
Cette section contient les exemples suivants sur la façon d'appeler des opérations de service à l'aide de la bibliothèque cliente Services de données WCF :
Appel d'Execute<T> pour retourner une collection d'entités
L'exemple suivant appelle une opération de service nommée GetOrdersByCity, qui accepte un paramètre de chaîne city et retourne un 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);
}
Dans cet exemple, l'opération de service retourne une collection d'objets Order avec les objets Order_Detail associés.
Utilisation de CreateQuery<T> pour retourner une collection d'entités
L'exemple suivant utilise CreateQuery<T>(String) pour retourner un DataServiceQuery<TElement>, utilisé pour appeler la même opération de service GetOrdersByCity :
' 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);
}
Dans cet exemple, la méthode AddQueryOption(String, Object) est utilisée pour ajouter le paramètre à la requête et la méthode Expand(String) est utilisée pour inclure les objets Order_Details associés dans les résultats.
Appel d'Execute<T> pour retourner une entité unique
L'exemple suivant appelle une opération de service nommée GetNewestOrder, qui retourne une seule entité 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);
}
Dans cet exemple, la méthode FirstOrDefault<TSource>(IEnumerable<TSource>) permet de demander l'exécution d'une seule entité Order.
Appel d'Execute<T> pour retourner une collection de valeurs primitives
L'exemple suivant appelle une opération de service qui retourne une collection de valeurs de chaîne :
' 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);
}
Appel d'Execute<T> pour retourner une valeur primitive unique
L'exemple suivant appelle une opération de service qui retourne une valeur de chaîne unique :
' 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);
}
Dans cet exemple également, la méthode FirstOrDefault<TSource>(IEnumerable<TSource>) permet de demander l'exécution d'une seule valeur entière.
Appel d'une opération de service qui ne retourne pas de données
L'exemple suivant appelle une opération de service qui ne retourne aucune donnée :
' 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);
}
Étant donné qu'aucune donnée n'est retournée, la valeur de l'exécution n'est pas assignée. Le seul élément indiquant que la requête a réussi est qu'aucune exception DataServiceQueryException n'est levée.
Appel d'une opération de service de façon asynchrone
L'exemple suivant appelle une opération de service de façon asynchrone en appelant BeginExecute<TElement>(Uri, AsyncCallback, Object) et 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);
}
}
Étant donné qu'aucune donnée n'est retournée, la valeur retournée par l'exécution n'est pas assignée. Le seul élément indiquant que la requête a réussi est qu'aucune exception DataServiceQueryException n'est levée.
L'exemple suivant appelle la même opération de service de façon asynchrone à l'aide de 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);
}
}