Como: chamar operações assíncronas usando uma fábrica de canais

Este tópico aborda como um cliente pode acessar uma operação de serviço de forma assíncrona ao usar um aplicativo cliente baseado em ChannelFactory<TChannel>. (Ao usar um objeto System.ServiceModel.ClientBase<TChannel> para invocar um serviço, você pode usar o modelo de chamada assíncrono controlado por eventos. Para obter mais informações, confira Como chamar operações de serviço de forma assíncrona. Para saber mais sobre o modelo de chamada assíncrona baseado em eventos, confira Padrão Assíncrono Baseado em Eventos (EAP).

O serviço neste tópico implementa a interface ICalculator. O cliente pode chamar as operações nessa interface de forma assíncrona, o que significa que operações como Add são divididas em dois métodos, BeginAdd e EndAdd, sendo a primeira aquela que inicia a chamada e a última a que recupera o resultado quando a operação é concluída. Para obter um exemplo mostrando como implementar uma operação de forma assíncrona em um serviço, confira Como implementar uma operação de serviço assíncrona. Para obter detalhes sobre operações síncronas e assíncronas, confira Operações síncronas e assíncronas.

Procedimento

Para chamar operações de serviço do WCF de maneira assíncrona

  1. Execute a Ferramenta Utilitário de Metadados ServiceModel (Svcutil.exe) com a opção /async, conforme mostrado no comando a seguir.

    svcutil /n:http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples http://localhost:8000/servicemodelsamples/service/mex /a
    

    Isso gera uma versão de cliente assíncrona do contrato de serviço para a operação.

  2. Crie uma função 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.

    static void AddCallback(IAsyncResult ar)
    {
        double result = ((CalculatorClient)ar.AsyncState).EndAdd(ar);
        Console.WriteLine("Add Result: {0}", result);
    }
    
    Private Shared Sub AddCallback(ByVal ar As IAsyncResult)
        Dim result = (CType(ar.AsyncState, CalculatorClient)).EndAdd(ar)
        Console.WriteLine("Add Result: {0}", result)
    End Sub
    
  3. Para acessar uma operação de serviço de forma assíncrona, crie o cliente e chame o Begin[Operation] (por exemplo BeginAdd) e especifique uma função de retorno de chamada, conforme mostrado no código de exemplo a seguir.

    ChannelFactory<ICalculatorChannel> factory = new ChannelFactory<ICalculatorChannel>();
    ICalculatorChannel channelClient = factory.CreateChannel();
    
    // BeginAdd
    double value1 = 100.00D;
    double value2 = 15.99D;
    
    IAsyncResult arAdd = channelClient.BeginAdd(value1, value2, AddCallback, channelClient);
    Console.WriteLine("Add({0},{1})", value1, value2);
    
    Dim factory As New ChannelFactory(Of ICalculatorChannel)()
    Dim channelClient As ICalculatorChannel = factory.CreateChannel()
    
    ' BeginAdd
    Dim value1 = 100.0R
    Dim value2 = 15.99R
    
    Dim arAdd As IAsyncResult = channelClient.BeginAdd(value1, value2, AddressOf AddCallback, channelClient)
    Console.WriteLine("Add({0},{1})", value1, value2)
    

    Quando a função de retorno de chamada é executada, o cliente chama End<operation> (por exemplo, EndAdd) para recuperar o resultado.

Exemplo

O serviço realizado com o código do cliente usado no procedimento anterior implementa a interface ICalculator, conforme mostrado no código a seguir. No lado do serviço, as operações Add e Subtract do contrato são invocadas de forma síncrona pelo tempo de execução do WCF (Windows Communication Foundation), embora as etapas anteriores do cliente sejam invocadas de forma assíncrona no cliente. As operações Multiply e Divide são usadas para invocar o serviço de forma assíncrona no lado do serviço, mesmo que o cliente as invoque de forma síncrona. Este código define a propriedade AsyncPatterncomo true. Essa configuração de propriedade, em combinação com a implementação do padrão assíncrono do .NET Framework, instrui o runtime a invocar a operação de modo assíncrono.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract]
    double Add(double n1, double n2);

    [OperationContract]
    double Subtract(double n1, double n2);

    //Multiply involves some file I/O so we'll make it Async.
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginMultiply(double n1, double n2, AsyncCallback callback, object state);
    double EndMultiply(IAsyncResult ar);

    //Divide involves some file I/O so we'll make it Async.
    [OperationContract(AsyncPattern = true)]
    IAsyncResult BeginDivide(double n1, double n2, AsyncCallback callback, object state);
    double EndDivide(IAsyncResult ar);
}
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _
Public Interface ICalculator
    <OperationContract> _
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double

    <OperationContract> _
    Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double

    'Multiply involves some file I/O so we'll make it Async.
    <OperationContract(AsyncPattern:=True)> _
    Function BeginMultiply(ByVal n1 As Double, ByVal n2 As Double, ByVal callback As AsyncCallback, ByVal state As Object) As IAsyncResult
    Function EndMultiply(ByVal ar As IAsyncResult) As Double

    'Divide involves some file I/O so we'll make it Async.
    <OperationContract(AsyncPattern:=True)> _
    Function BeginDivide(ByVal n1 As Double, ByVal n2 As Double, ByVal callback As AsyncCallback, ByVal state As Object) As IAsyncResult
    Function EndDivide(ByVal ar As IAsyncResult) As Double
End Interface