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:
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.