WCF Web API – Suporte à JSONP


Uma das grandes necessidades no consumo de serviços por parte das aplicações Web, é consumir serviços criados e que estão além da própria aplicação cliente, que provavelmente estará debaixo de um outro domínio, e por questões de segurança, isso não será permitido diretamente, já que se utilizado de forma maliciosa e sem o consentimento do usuário, pode por em risco as informações e a navegação dos usuários.

Para contornar essa “limitação”, então precisamos de alguma técnica para possibilitar que essa tarefa seja realizada. Uma opção seria a criação de um serviço nesta aplicação cliente, que serviria como um wrapper, e este por sua vez, consumiria diretamente o serviço, sem as imposições de chamada entre domínios que o navegador impõe. Com isso, o código JavaScript irá consumir este serviço local, que por sua vez, encaminharia a requisição para o serviço remoto, em outro domínio.

Apesar desta técnica funcionar, ela acaba sendo uma solução ruim, já que teremos que envolver outros elementos para realizar uma tarefa relativamente simples. Felizmente o jQuery fornece nativamente o suporte a uma técnica conhecida como JSONP (JSON with Padding).

O seu funcionamento não é muito complicado. Como disse acima, requisições entre domínios não são permitidas, mas há uma única exceção: a tag , ou seja, podemos definir no elemento src (source) a URL para um recurso que está além do nosso domínio, que o navegador não irá proibir o acesso. O que o JSONP faz é justamente o uso dela, criando dinamicamente esta tag, e definindo no atributo src a URL do serviço que estamos tentando acessar.

Na verdade isso não funciona sozinho, ou seja, precisa de uma certa colaboração por parte do serviço, para que o cliente possa processar o resultado da forma correta. Além dos parâmetros que são exigidos pelo método do serviço, o jQuery inclui um parâmetro chamado callback, que é o nome de uma função criada temporariamente no cliente. Aqui entra em cena a infraestrutura do serviço, que deve ser capaz de retornar o resultado (dados) envolvido nesta função, e quando o mesmo chegar ao cliente, ele invocará para capturar o resultado e encaminhá-lo para o nosso código, e assim iremos manipular da forma que acharmos mais conveniente. Falaremos da implementação por parte do serviço mais tarde.

Para fazer tudo isso funcionar, precisamos nos atentar à alguns detalhes do lado do cliente e do lado do serviço. Do lado do cliente, tudo o que precisamos fazer é indicar para a API de AJAX do jQuery que ela deve utilizar JSONP. Para isso, devemos recorrer ao atributo dataType, que indica o tipo de dado/formato que você está esperando que o servidor te retorne. No nosso caso, vamos apontar jsonp, assim como é mostrado no código abaixo:

    $(document).ready(function () {
        $.ajax(
        {
            type: ‘GET’,
            url: ‘http://ipv4.fiddler:1191/cotacoes’,
            dataType: ‘jsonp’,
            success: function (cotacoes) {
                var itens = [];

                $.each(cotacoes, function (indice, cotacao) {
                    itens.push(‘

  • ‘ + cotacao.Moeda + ‘: ‘ + cotacao.ValorEmReal + ‘
  • ‘);
                    });

                    $(‘

      ‘, { html: itens.join(”) }).appendTo($(‘#Cotacoes’));
              }
          });
      });

      </head>
      <body>
         

         

      </body>
      </html>

      Por parte do cliente, o jQuery fornece parâmetros para realizarmos a configuração via JSONP. Como podemos perceber no código acima, em negrito temos do tipo da requisição sendo definido como JSONP, o que faz com que a requisição seja formatada da seguinte forma (repare o que temos em negrito):

      GET http://127.0.0.1:1191/cotacoes?callback=jQuery15109440240194135102_1328569080908&_=1328569080915 HTTP/1.1
      Accept: application/javascript, */*;q=0.8
      Referer: http://ipv4.fiddler:1185/Index.htm
      Accept-Language: en-US,pt-BR;q=0.5
      User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
      Accept-Encoding: gzip, deflate
      Host: 127.0.0.1:1191
      Connection: Keep-Alive

      Como disse acima, é necessário que o serviço também de suporte à esta funcionalidade. A versão atual do WCF Web API, que está na 0.6, já traz esse recurso nativamente, e com poucas (talvez nenhuma) configurações, podemos construir e expor o serviço para que ele seja consumido através de um cliente que esteja hospedado em um outro domínio. Para o exemplo, temos um serviço “dummy” de cotação de câmbio, que possui os dados estáticos. Apenas como observação, não é mais necessário que o serviço seja decorado com o atributo ServiceContractAttribute.

      public class ServicoDeCotacoes
      {
          [WebGet]
          public IEnumerable<Cotacao> RecuperarCotacoes()
          {
              return new[]
              { 
                  new Cotacao() { Moeda = “Dólar Americano”, ValorEmReal = 1.7263M },
                  new Cotacao() { Moeda = “Euro”, ValorEmReal = 2.2653M },
                  new Cotacao() { Moeda = “Libra”, ValorEmReal = 2.7308M }
              };
          }
      }

      Finalmente, tudo o que precisamos fazer com o serviço é configurá-lo através da classe WebApiConfiguration, algo como já era realizado nas versões anteriores desta API. Abaixo temos um código simples, que ilustra como procedemos para realizar tal configuração:

      public class MvcApplication : System.Web.HttpApplication
      {
          protected void Application_Start()
          {
              ConfigurarServico();
          }

          private static void ConfigurarServico()
          {
              RouteTable.Routes.MapServiceRoute<ServicoDeCotacoes>(
                  “cotacoes”,
                  new WebApiConfiguration()
                  {
                      CreateInstance = (t, ic, msg) => new ServicoDeCotacoes()
                  });
          }
      }

      Ao executar a requisição para o serviço e interceptando-a, teremos na resposta da mesma, a função criada dinamicamente no cliente que será executada automaticamente pelo próprio jQuery. Mais uma vez, repare o que temos negritado abaixo. Note que o nome da função que foi criado pelo jQuery e repassado para o serviço, é devolvido para o mesmo.

      HTTP/1.1 200 OK
      Server: ASP.NET Development Server/10.0.0.0
      Date: Mon, 06 Feb 2012 22:58:00 GMT
      X-AspNet-Version: 4.0.30319
      jsonp-callback: jQuery15109440240194135102_1328569080908
      Content-Length: 170
      Cache-Control: private
      Content-Type: application/javascript; charset=utf-8
      Connection: Close

      jQuery15109440240194135102_1328569080908([{“Moeda”:”Dólar Americano”,”ValorEmReal”:1.7263},{“Moeda”:”Euro”,”ValorEmReal”:2.2653},{“Moeda”:”Libra”,”ValorEmReal”:2.7308}])

      Nenhuma configuração extra foi realizada por parte do serviço, porque a Microsoft entende que isso seja uma necessidade comum, o que faz com que já venha devidamente configurado. Internamente temos um operation response handler chamado JsonpHttpResponseHandler, que é responsável por avaliar se a requisição é ou não uma requisição do tipo JSONP, e para isso, verifica se há uma querystring chamada callback. Caso queira alterar o nome desta querystring, pode-se recorrer à propriedade CallbackQueryParameter deste próprio handler.

      Além disso, ainda temos um media type customizado, chamado de JsonpMediaTypeFormatter, que envolve o resultado gerado pelo serviço, pela função (callback) criada pelo jQuery, que entenderá isso como o resultado que será repassado para a função de sucesso, configurada na chamada do método $.ajax.

      Anúncios

    Deixe uma resposta

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

    Logotipo do WordPress.com

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

    Imagem do Twitter

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

    Foto do Facebook

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

    Foto do Google+

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

    Conectando a %s