Callback com WCF

Olá pessoal,

Dando continuidade ao post Operações One-Way com WCF, resolvi escrever sobre uma tecnologia complementar que é o callback. O callback permite que o serviço WCF chame operações para serem executadas no lado do cliente, sendo bastante útil se utilizado em conjunto com operações one-way em cenários de longa duração.

Neste tipo de uso o cliente chama uma operação one-way, não precisa esperar o retorno do serviço e sua thread está liberada para outros processamentos, o serviço realiza o seu trabalho e quando necessário, por exemplo, no término do processamento, envia mensagens para o cliente através do callback. O diagrama de sequência abaixo ilustra o processo de comunicação:

image

Para que a comunicação ocorra com sucesso, é necessário que o binding utilizado suporte callback, os bindings NetTcpBinding e NetNamedPipeBinding suportam callback, pois funcionam em cima de protocolos que suportam comunicação bidirecional. Já o protocolo HTTP não suporta este tipo de comunicação, fazendo com que os bindings BasicHttpBinding ou WSHttpBinding não suportem callback. Uma alternativa para callback com HTTP é o uso do WSDualHttpBinding, que abre dois canais de comunicação HTTP: um para chamadas no sentido do cliente para o serviço e outro para chamadas do serviço para o cliente.

Para que o serviço WCF entenda o callback, é necessário definir um contrato de callback com suas operações e também indicar no ServiceContract qual o tipo que deve ser utilizado para callback, o código fica similar ao código abaixo:

 interface IContractCallback
{
    [OperationContract(IsOneWay=true)]
    void OnCallback();
}
 [ServiceContract(CallbackContract = typeof(IContractCallback))]
public interface IService
{
    [OperationContract(IsOneWay=true)]
    void ProcessarOneWay();
}

Do lado do cliente, é necessário informar ao serviço qual objeto é o responsável pelo callback. Para isso é necessário implementar a interface de callback e também passar uma instância desta classe para o contexto co WCF, conforme abaixo:

 class MyCallback :  CallbackServiceReference.IServiceCallback
{
    public void OnCallback()
    {
        MessageBox.Show("OnCallback");
    }
}
 private void button1_Click(object sender, RoutedEventArgs e)
{
    CallbackServiceReference.IServiceCallback callback = new MyCallback();
            
    InstanceContext ctx = new InstanceContext(callback);
            
    CallbackServiceReference.ServiceClient proxy = 
        new CallbackServiceReference.ServiceClient(ctx);

    proxy.ProcessarOneWay();
}

Já do lado do serviço precisamos acessar a instância informada do objeto que gerencia o callback para conseguirmos chamar suas operações, isso deve ser feito utilizando o OperationContext, sempre utilizando a interface definida no contrato de callback, conforme abaixo:

 public void ProcessarOneWay()
{
    Trace.WriteLine(
        string.Format("Início ProcessarOneWay - {0}", DateTime.Now));
            
    Thread.Sleep(15000);
            
    Trace.WriteLine(
        string.Format("Fim ProcessarOneWay - {0}", DateTime.Now));

    IContractCallback callback = 
        OperationContext.Current.GetCallbackChannel<IContractCallback>();

    callback.OnCallback();
}

Com isso, é possível utilizar a infraestrutura do WCF para cenários de comunicação mais complexos entre cliente e serviço, atendendo à diversos cenários de uso. O código fonte utilizado pode ser baixado aqui.