Funcionamento do WSDualHttpBinding no cliente

Uma das possibilidades dentro do WCF é a capacidade que o serviço tem de invocar um callback para o cliente, permitindo que este método client-side seja executado e, conseqüentemente, o cliente possa interagir com o serviço, simulando os tradicionais eventos.

Nativamente os bindings NetTcpBinding e NetNamedPipeBinding fazem isso nativamente, devido aos respectivos protocolos utilizados. Além desses, há um binding chamado do WSDualHttpBinding que tem essa mesma finalidade mas, como o próprio nome diz, utilizando o protocolo HTTP. A imagem abaixo ilustra esse processo acontecendo entre o cliente e o serviço:

Quando você faz o uso do WSDualHttpBinding, o WCF utilizará um canal diferente para invocar o callback. Internamente, o que acaba sendo feito do lado do cliente – por parte do runtime do WCF – é a criação de um “endpoint” (incluindo uma porta disponível) para que o serviço relacionado consiga invocá-lo. Esse endereço temporário criado pelo WCF, é registrado sob o Http.sys (mais detalhes aqui) que é um componente de baixo nível e que faz parte do sistema de comunicação do Windows. Sendo assim, qualquer requisição que chegar para esse “endpoint”, o Http.sys encaminhará para o runtime do WCF que, finalmente, irá disparar a classe que implementa a interface de callback que, por sua vez, foi fornecida pelo contrato do serviço.

Finalmente, todo esse processo ocorre de forma transparente, permitindo que aplicações distribuídas, rodando como cliente WCF, possam disponibilizar um ponto de comunicação para essa interação.

WCF Visualizer

Está aqui uma ferramenta muito interessante. Trata-se de um Debugger Visualizer para WCF. Uma vez instalado no Visual Studio, voce poderá analisar, durante a depuração do código, toda a configuração aplicada ao objeto ServiceHost.

Habilitando o Health Monitoring no WCF

O ASP.NET 2.0 introduziu uma nova API chamada de Health Monitoring. Esta API permite-nos, de forma flexível, ajustar o log/auditoria de uma aplicação ASP.NET. Como sabemos, podemos hospedar um serviço WCF dentro de uma aplicação ASP.NET e, sendo assim, poderíamos utilizar esta mesma API para conseguirmos logar possíveis eventos (isso pode incluir exceções) que o serviço venha a disparar.

Basicamente o que precisamos fazer é criar um evento customizado para o WCF e configurá-lo como já acontecia (isso é mostrado em detalhes neste artigo). Uma vez que o evento é criado, podemos anexá-lo dentro do runtime do WCF, mas isso exige algumas técnicas. A primeira delas é implementar a Interface IErrorHandler que, por sua vez, disponibiliza dois métodos: HandleError e ProvideFault. O método HandleError é sempre invocado quando alguma exceção ocorre dentro do serviço e, é fornecido para esse método um parametro do tipo Exception que representa o erro ocorrido. É no interior deste método que devemos criar o evento, definir a mensagem e, finalmente, invocar o método Raise para persistí-lo no provider especificado na configuração do Health Monitoring (mais adiante).

Para concluir, ainda é necessário implementar a Interface IServiceBehavior que fornece um mecanismo para interceptar e inserir comportamentos específicos ao serviço como um todo. Nos métodos fornecidos por essa Interface, utilizaremos o ApplyDispatchBehavior, que nos permitirá adicionar extensões, como error handlers (tema do post), interceptors, etc.. Abaixo a classe que implementa essas Interfaces e também a Interface do contrato do serviço:

public class ServiceImpl : IData, IServiceBehavior, IErrorHandler
{
    public string Teste(string value)
    {
        if (string.IsNullOrEmpty(value))
            throw new FaultException<ArgumentNullException>(new ArgumentNullException(“value”));

        return “Ola ” + value;
    }

    public void AddBindingParameters(…) { }

    public void ApplyDispatchBehavior(…)
    {
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            dispatcher.ErrorHandlers.Add(this);
    }

    public void Validate(…) { }

    public bool HandleError(Exception error)
    {
        new WCFErrorEvent(error.ToString(), null, 0).Raise();
        return true;
    }

    public void ProvideFault(…) { }
}

Para o exemplo, eu implementei as duas Interfaces na mesma classe de serviço, o que não é muito aconselhável, já que polui muito o código, misturando características do runtime com a regra de negócio. Se notarem, dentro do método ApplyDispatchBehavior adicionamos em todos na coleção de dispatcher channels a instancia corrente da classe para que, no momento em que o erro for disparado, esse tratamento/log seja efetuado.

Para finalizar, apenas resta especificar a configuração do Health Monitoring dentro do arquivo Web.Config da aplicação para que finalmente todos os eventos sejam persistidos.

<healthMonitoring enabled=”true”>
  <eventMappings>
    <add name=”WCF Error Event” type=”MyService.WCFErrorEvent”/>
  </eventMappings>
  <rules>
    <clear/>
    <add
      name=”All Errors Default”
      eventName=”WCF Error Event”
      provider=”EventLogProvider”
      profile=”Default”
      minInterval=”00:01:00″/>
  </rules>
</healthMonitoring>