Comment : appeler des opérations de service WCF de façon asynchrone
Cet article explique comment un client peut accéder de façon asynchrone à une opération de service. Le service utilisé dans cet article implémente l'interface ICalculator
. Le client peut appeler les opérations sur cette interface de manière asynchrone à l'aide du modèle d'appel asynchrone commandé par événement. (Pour plus d'informations sur le modèle d'appel asynchrone basé sur des événements, consultez Programmation multithread avec le modèle asynchrone basé sur des événements). Pour obtenir un exemple montrant comment implémenter une opération de façon asynchrone dans un service, consultez Guide pratique pour implémenter une opération de service asynchrone. Pour plus d'informations sur les opérations synchrones et asynchrones, consultez Opérations synchrones et asynchrones.
Notes
Le modèle d'appel asynchrone commandé par événement n'est pas pris en charge lorsqu'il utilise un ChannelFactory<TChannel>. Pour plus d’informations sur les appels asynchrones effectués avec ChannelFactory<TChannel>, consultez Guide pratique pour appeler des opérations de façon asynchrone à l’aide d’une fabrique de canaux.
Procédure
Pour appeler des opérations de service WCF de façon asynchrone
Exécutez l'outil ServiceModel Metadata Utility Tool (Svcutil.exe) en définissant les deux options
/async
et/tcv:Version35
comme illustré dans la commande suivante.svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35
Cette opération génère, en plus des opérations asynchrones basées sur les délégués standard et des opérations synchrones, un client WCF qui contient :
Deux opérations
<operationName>``Async
à utiliser avec le modèle d’appel asynchrone basé sur des événements. Par exemple :public void AddAsync(double n1, double n2) { this.AddAsync(n1, n2, null); } public void AddAsync(double n1, double n2, object userState) { if ((this.onBeginAddDelegate == null)) { this.onBeginAddDelegate = new BeginOperationDelegate(this.OnBeginAdd); } if ((this.onEndAddDelegate == null)) { this.onEndAddDelegate = new EndOperationDelegate(this.OnEndAdd); } if ((this.onAddCompletedDelegate == null)) { this.onAddCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnAddCompleted); } base.InvokeAsync(this.onBeginAddDelegate, new object[] { n1, n2}, this.onEndAddDelegate, this.onAddCompletedDelegate, userState); }
Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double) Me.AddAsync(n1, n2, Nothing) End Sub Public Overloads Sub AddAsync(ByVal n1 As Double, ByVal n2 As Double, ByVal userState As Object) If (Me.onBeginAddDelegate Is Nothing) Then Me.onBeginAddDelegate = AddressOf Me.OnBeginAdd End If If (Me.onEndAddDelegate Is Nothing) Then Me.onEndAddDelegate = AddressOf Me.OnEndAdd End If If (Me.onAddCompletedDelegate Is Nothing) Then Me.onAddCompletedDelegate = AddressOf Me.OnAddCompleted End If MyBase.InvokeAsync(Me.onBeginAddDelegate, New Object() {n1, n2}, Me.onEndAddDelegate, Me.onAddCompletedDelegate, userState) End Sub
Les événements terminés d'opération de la forme
<operationName>``Completed
à utiliser avec le modèle d’appel asynchrone basé sur des événements. Par exemple :public event System.EventHandler<AddCompletedEventArgs> AddCompleted;
Public Event AddCompleted As System.EventHandler(Of AddCompletedEventArgs)
Les types System.EventArgs pour chaque opération (de la forme
<operationName>``CompletedEventArgs
) à utiliser avec le modèle d’appel asynchrone basé sur des événements. Par exemple :[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class AddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { private object[] results; public AddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : base(exception, cancelled, userState) { this.results = results; } public double Result { get { base.RaiseExceptionIfNecessary(); return ((double)(this.results[0])); } } }
<System.Diagnostics.DebuggerStepThroughAttribute(), _ System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")> _ Partial Public Class AddCompletedEventArgs Inherits System.ComponentModel.AsyncCompletedEventArgs Private results() As Object Public Sub New(ByVal results() As Object, ByVal exception As System.Exception, ByVal cancelled As Boolean, ByVal userState As Object) MyBase.New(exception, cancelled, userState) Me.results = results End Sub Public ReadOnly Property Result() As Double Get MyBase.RaiseExceptionIfNecessary Return CType(Me.results(0),Double) End Get End Property End Class
Dans l'application d'appel, créez une méthode de rappel à appeler au terme de l'opération asynchrone en vous conformant à l'exemple de code suivant.
// Asynchronous callbacks for displaying results. static void AddCallback(object sender, AddCompletedEventArgs e) { Console.WriteLine("Add Result: {0}", e.Result); }
' Asynchronous callbacks for displaying results. Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs) Console.WriteLine("Add Result: {0}", e.Result) End Sub
Avant d’appeler l’opération, utilisez un nouveau System.EventHandler<TEventArgs> générique de type
<operationName>``EventArgs
pour ajouter la méthode de gestionnaire (créée à l’étape précédente) à l’événement<operationName>``Completed
. Appelez ensuite la méthode<operationName>``Async
. Par exemple :// AddAsync double value1 = 100.00D; double value2 = 15.99D; client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback); client.AddAsync(value1, value2); Console.WriteLine("Add({0},{1})", value1, value2);
' AddAsync Dim value1 As Double = 100 Dim value2 As Double = 15.99 AddHandler client.AddCompleted, AddressOf AddCallback client.AddAsync(value1, value2) Console.WriteLine("Add({0},{1})", value1, value2)
Exemple
Notes
Les règles de conception pour le modèle asynchrone basé sur les événements stipulent que si plusieurs valeurs sont retournées, une valeur est retournée comme la propriété Result
et les autres sont retournées comme les propriétés sur l'objet EventArgs. Il en découle que si un client importe des métadonnées à l'aide des options de commande asynchrone basées sur les événements et que l'opération retourne plusieurs valeurs, l'objet EventArgs par défaut retourne une valeur comme la propriété Result
et le reste sont des propriétés de l'objet EventArgs. Pour recevoir l'objet message comme la propriété Result
et que les valeurs retournées sur cet objet soient des propriétés, utilisez l'option de commande /messageContract
. Cette opération génère une signature qui retourne le message de réponse comme la propriété Result
sur l'objet EventArgs. Toutes les valeurs de retour internes sont ensuite des propriétés de l'objet de message de réponse.
using System;
namespace Microsoft.ServiceModel.Samples
{
// The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
class Client
{
static void Main()
{
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.");
Console.WriteLine();
// Create a client
CalculatorClient client = new CalculatorClient();
// AddAsync
double value1 = 100.00D;
double value2 = 15.99D;
client.AddCompleted += new EventHandler<AddCompletedEventArgs>(AddCallback);
client.AddAsync(value1, value2);
Console.WriteLine("Add({0},{1})", value1, value2);
// SubtractAsync
value1 = 145.00D;
value2 = 76.54D;
client.SubtractCompleted += new EventHandler<SubtractCompletedEventArgs>(SubtractCallback);
client.SubtractAsync(value1, value2);
Console.WriteLine("Subtract({0},{1})", value1, value2);
// Multiply
value1 = 9.00D;
value2 = 81.25D;
double result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
// Divide
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
// Asynchronous callbacks for displaying results.
static void AddCallback(object sender, AddCompletedEventArgs e)
{
Console.WriteLine("Add Result: {0}", e.Result);
}
static void SubtractCallback(object sender, SubtractCompletedEventArgs e)
{
Console.WriteLine("Subtract Result: {0}", e.Result);
}
}
}
Namespace Microsoft.ServiceModel.Samples
' The service contract is defined in generatedClient.vb, generated from the service by the svcutil tool.
Class Client
Public Shared Sub Main()
Console.WriteLine("Press <ENTER> to terminate client once the output is displayed.")
Console.WriteLine()
' Create a client
Dim client As New CalculatorClient()
' AddAsync
Dim value1 As Double = 100
Dim value2 As Double = 15.99
AddHandler client.AddCompleted, AddressOf AddCallback
client.AddAsync(value1, value2)
Console.WriteLine("Add({0},{1})", value1, value2)
' SubtractAsync
value1 = 145
value2 = 76.54
AddHandler client.SubtractCompleted, AddressOf SubtractCallback
client.SubtractAsync(value1, value2)
Console.WriteLine("Subtract({0},{1})", value1, value2)
' Multiply
value1 = 9
value2 = 81.25
Dim result As Double = client.Multiply(value1, value2)
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result)
' Divide
value1 = 22
value2 = 7
result = client.Divide(value1, value2)
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result)
Console.ReadLine()
'Closing the client gracefully closes the connection and cleans up resources
client.Close()
End Sub
' Asynchronous callbacks for displaying results.
Private Shared Sub AddCallback(ByVal sender As Object, ByVal e As AddCompletedEventArgs)
Console.WriteLine("Add Result: {0}", e.Result)
End Sub
Private Shared Sub SubtractCallback(ByVal sender As Object, ByVal e As SubtractCompletedEventArgs)
Console.WriteLine("Subtract Result: {0}", e.Result)
End Sub
End Class
End Namespace