Como: Chamar operações de forma assíncrona 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 ChannelFactory<TChannel>aplicativo cliente baseado em síncrono. (Ao usar um System.ServiceModel.ClientBase<TChannel> objeto para invocar um serviço, você pode usar o modelo de chamada assíncrona controlado por eventos. Para obter mais informações, consulte Como chamar operações de serviço de forma assíncrona. Para obter mais informações sobre o modelo de chamada assíncrona baseada em evento, consulte Padrão assíncrono baseado em evento (EAP).)

O serviço neste tópico implementa a ICalculator interface. 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, o primeiro dos quais inicia a chamada e o segundo 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, consulte Como implementar uma operação de serviço assíncrona. Para obter detalhes sobre operações síncronas e assíncronas, consulte Operações síncronas e assíncronas.

Procedimento

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

  1. Execute a ferramenta ServiceModel Metadata Utility Tool (Svcutil.exe) com a /async opção mostrada 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 que é usado com o código de cliente que é usado no procedimento anterior implementa a ICalculator interface como mostrado no código a seguir. No lado do serviço, as Add operações e Subtract do contrato são invocadas de forma síncrona pelo tempo de execução do Windows Communication Foundation (WCF), mesmo que as etapas anteriores do cliente sejam invocadas de forma assíncrona no cliente. As Multiply operações 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 exemplo define a AsyncPattern propriedade como true. Essa configuração de propriedade, em combinação com a implementação do padrão assíncrono do .NET Framework, informa ao tempo de execução para invocar a operação de forma assíncrona.

[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