Como chamar operações de serviço do WCF de maneira assíncrona
Este artigo aborda como um cliente pode acessar uma operação de serviço de forma assíncrona. O serviço neste artigo implementa a interface ICalculator
. O cliente pode chamar as operações nessa interface de forma assíncrona usando o modelo de chamada assíncrona controlada por eventos. (Para obter mais informações sobre o modelo de chamada assíncrona controlada por eventos, consulte Programação multithreaded com o padrão assíncrono baseado em evento). Para obter um exemplo que mostra como implementar uma operação de forma assíncrona em um serviço, consulte Como implementar uma operação de serviço assíncrona. Para obter mais informações sobre operações síncronas e assíncronas, consulte Operações síncronas e assíncronas.
Observação
Não há suporte para o modelo de chamada assíncrona controlada por eventos ao usar um ChannelFactory<TChannel>. Para obter informações sobre como fazer chamadas assíncronas usando o ChannelFactory<TChannel>, consulte Como chamar operações de forma assíncrona usando uma fábrica de canais.
Procedimento
Para chamar operações de serviço WCF de maneira assíncrona
Execute a Ferramenta de Utilitário de Metadados ServiceModel (Svcutil.exe) com as opções de comando
/async
e/tcv:Version35
juntas, conforme mostrado no comando a seguir.svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a /tcv:Version35
Isso gera, além das operações síncronas e assíncronas baseadas em delegados padrão, uma classe de cliente WCF que contém:
Duas operações
<operationName>``Async
para uso com a abordagem de chamada assíncrona baseada em evento. Por exemplo: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
Operação de eventos concluída do formulário
<operationName>``Completed
para uso com a abordagem de chamada assíncrona baseada em evento. Por exemplo:public event System.EventHandler<AddCompletedEventArgs> AddCompleted;
Public Event AddCompleted As System.EventHandler(Of AddCompletedEventArgs)
System.EventArgs tipos para cada operação (no formulário
<operationName>``CompletedEventArgs
) para uso com a abordagem de chamada assíncrona baseada em evento. Por exemplo:[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
No aplicativo de chamada, crie um método de retorno de chamada a ser chamada quando a operação assíncrona for concluída, conforme mostrado no código de exemplo a seguir.
// 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
Antes de chamar a operação, use um novo genérico System.EventHandler<TEventArgs> do tipo
<operationName>``EventArgs
para adicionar o método manipulador (criado na etapa anterior) ao evento<operationName>``Completed
. Em seguida, chame o método<operationName>``Async
. Por exemplo:// 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)
Exemplo
Observação
As diretrizes de design do modelo assíncrono baseado em eventos declaram que, se mais de um valor for retornado, um valor será retornado como a propriedade Result
e os outros serão retornados como propriedades no objeto EventArgs. Um resultado disso é que, se um cliente importa metadados usando as opções de comando assíncronas baseadas em evento e a operação retorna mais de um valor, o objeto padrão EventArgs retorna um valor como a propriedade Result
e o restante são propriedades do objeto EventArgs. Se você quiser receber o objeto da mensagem como a propriedade Result
e ter os valores retornados como propriedades nesse objeto, use a opção de comando /messageContract
. Isso gera uma assinatura que retorna a mensagem de resposta como a propriedade Result
no objeto EventArgs. Todos os valores de retorno internos são propriedades do objeto da mensagem de resposta.
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