Utilizando async/await com proxies WCF


Como comentei anteriormente, a Microsoft está fazendo grandes melhorias para a próxima versão do C#, com o intuito de facilitar a programação assíncrona dentro do .NET Framework. No artigo mencionado, lá temos como proceder para invocar um código de forma assíncrona neste novo modelo, que é através da utilização da keyword async no método que deverá ser invocado de forma assíncrona, e dentro dele, utilizamos a keyword await, para dizer que a região a seguir trata-se de um callback.

Como sabemos, os delegates já trazem nativamente suporte para que eles sejam invocados de forma síncrona ou assíncrona. Mas como o modelo de programação muda partir destas novas funcionalidades que estão sendo criadas no C#, ou seja, passaremos a utilizar a classe Task<T> para representar o processo assíncrono, então podemos recorrer a um método chamado FromAsync da classe TaskFactory, que foi incluído no .NET Framework a partir da versão 4.0. Fazendo uso deste método, podemos invocar um delegate de forma assíncrona utilizando o seguinte código:

Func<string, string> ping = s => s + ” ping!”;

var task =
    Task.Factory.FromAsync<string, string>(
        ping.BeginInvoke, ping.EndInvoke, “Teste”, null);

Como podemos perceber no código acima, informamos para o método FromAsync o par de métodos Begin/End que compõem a chamada assíncrona para uma tarefa, dando origem assim à uma instância da classe Task, que daqui em diante, podemos utilizar em conjunto com o novo modelo que está sendo proposto pela Microsoft.

Mas como podemos utilizar esta técnica para consumir serviços WCF? Como já comentei neste artigo, podemos optar durante a referência para o serviço na aplicação cliente (Add Service Reference), por marcar a opção “Generate asynchronous operations”, e com isso, para cada operação existente no serviço, serão criadas três métodos, sendo um para a chamada síncrona, e os outros dois irão compor a chamada assíncrona (BeginNomDaOperacao/EndNomeDaOperacao). Sabendo que há como transformar o modelo de Begin/End em Tasks, poderíamos utilizar o código acima para consumir o serviço WCF de forma assíncrona e recorrer ao novo modelo. Mas ao invés de termos todo esse trabalho, já há uma forma de fazer com que o proxy também seja gerado com as opções de Tasks.

Para isso, utilizamos uma implementação que a Microsoft criou chamada de TaskAsyncWsdlImportExtension. Essa classe intercepta a referência do serviço na aplicação cliente, e cria a versão assíncrona baseando-se em Tasks para todas as operações que ele encontra no documento WSDL. Para isso funcionar, devemos referenciar a DLL que consta essa classe no projeto cliente (ela está incluída nos exemplos do CTP). Depois disso, devemos modificar o arquivo de configuração para definirmos essa estensão, assim como é mostrado através do código abaixo:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
 <system.serviceModel>
  <client>
   <metadata>
    <wsdlImporters>
     <extension type=”TaskWsdlImportExtension.TaskAsyncWsdlImportExtension, TaskWsdlImportExtension…” />
    </wsdlImporters>
   </metadata>
  </client>
 </system.serviceModel>
</configuration>

Em seguida, devemos efetuar a referência para o serviço e marcar a opção para a geração das operações assíncronas. Isso já é o suficiente para a classe TaskAsyncWsdlImportExtension entrar em ação e construir a nova versão deste método.

public partial class ContratoClient : ClientBase<IContrato>, IContrato
{
    public Task<string> PingAsync(string value)
    {
        return Task<string>.Factory.FromAsync(
            new Func<string, AsyncCallback, object, IAsyncResult>(((IContrato)(this)).BeginPing),
            new Func<IAsyncResult, string>(((IContrato)(this)).EndPing), value, null);
    }
}

A partir de agora, podemos efetivamente recorrer ao novo modelo de programação assíncrona do C#, ou seja, com a instância da classe Task em mãos, podemos fazer uso dela dentro de métodos marcados como async e, consequentemente, utilizar a keyword await para determinar o que queremos fazer com o resultado quando ele for devolvido. Note que o código fica bem mais sucinto quando comparado ao modelo Begin/End que fazemos atualmente.

private async static void InvocarServico()
{
    var temp = await proxy.PingAsync(“Algum Valor”);
    Console.WriteLine(“O resultado foi: {0}”, temp);
}

Publicidade

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s