Desenvolvimento - WCF
Consumindo serviços WCF com jQuery
A finalidade deste artigo é mostrar como proceder para criar serviços WCF que possam ser consumidos pelo AJAX, e depois disso, vamos analisar o que o jQuery oferece para o consumo do mesmo.
por Israel AéceO jQuery é uma biblioteca com várias funcionalidades que tornam o desenvolvimento de código JavaScript muito mais simples. Tarefas que demandavam várias linhas de código para chegar a um determinado resultado, atualmente com o jQuery o código necessário para atingir esse mesmo objetivo é muito menos complexo. Inclusive a Microsoft reconheceu a facilidade e a larga adoção pelos desenvolvedores, e decidiu incorporá-lo às templates de projeto do ASP.NET.
Entre as mais variadas funcionalidades que o jQuery oferece, uma delas é o suporte ao AJAX, que nos permite invocar métodos que estão do lado do servidor. Mas além disso, uma das possibilidades que temos é a requisição para serviços, incluindo serviços construídos com WCF. A finalidade deste artigo é mostrar como proceder para criar serviços WCF que possam ser consumidos pelo AJAX, e depois disso, vamos analisar o que o jQuery oferece para o consumo do mesmo.
Primeiramente vamos nos atentar a construção de um serviço para que possamos consumí-lo através do AJAX/jQuery. O que precisamos nos atentar é que para expor esse serviço para clientes AJAX, é necessário decorarmos as operações não somente com o atributo OperationContractAttribute, mas também com os atributos WebGetAttribute ou WebInvokeAttribute, que são disponibilizados a partir da versão 3.5 do .NET Framework, e que estão contidos debaixo do namespace System.ServiceModel.Web (assembly System.ServiceModel.Web.dll).
Como exemplo, o contrato irá manipular instância da classe Usuario, que nada mais é do que um objeto simples, que possui três propriedades autoexplicativas: Codigo, Nome e Email. O contrato fornecerá três operações: RecuperarUsuario, que retorna a instância da classe Usuario devidamente configurada com os parâmetros de entrada, uma outra operação chamada RecuperarUsuarios que retorna uma coleção de usuários e, finalmente, a operação Adicionar, que dado a instância do usuário, irá adicioná-lo em algum repositório. Abaixo podemos visualizar a interface que servirá como o contrato para o serviço:
[ServiceContract]
public interface IUsuarios
{
[OperationContract]
[WebInvoke(
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Usuario RecuperarUsuario(string nome, string email);
[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
Usuario[] RecuperarUsuarios();
[OperationContract]
[WebInvoke(
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
void Adicionar(Usuario usuario);
}
Note que as operações que serão expostas também determinam algumas configurações específicas para quando forem consumidas a partir do AJAX. É importante perceber também que em todas elas, estamos optando por trabalhar com JSON ao invés do XML para formular a mensagem de requisição e de resposta, já que o JSON é mais simples de se trabalhar com Javascript. A propriedade BodyStyle controla como o corpo da requisição/resposta deve ser formatado, determinando se os parâmetros ou o resultado dos métodos devem ou não estar dentro de elementos adicionais. Para maiores detalhes sobre esses parâmetros, consulte este artigo.
Ao interceptar a requisição/resposta que é feita para a primeira operação, então teremos as informações em JSON sendo trafegadas, e as duas pontas (WCF e o jQuery) se encarregam de fazer toda a tradução necessária, aliviando assim nosso trabalho. Antes de analisarmos o código necessário para consumir serviços WCF no jQuery, vamos analisar o conteúdo que está sendo trafegado para as mensagens (requisição e resposta respectivamente) do contrato que criamos acima:
[ Operação RecuperarUsuario ]
POST http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario HTTP/1.1
Content-Type: application/json
-- OUTROS PARAMETROS OMITIDOS --
{ "nome": "Israel Aece", "email": "ia@israelaece.com" }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
-- OUTROS PARAMETROS OMITIDOS --
{"RecuperarUsuarioResult":{"Codigo":123,"Email":"ia@israelaece.com","Nome":"Israel Aece"}}
[ Operação RecuperarUsuarios ]
GET http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuarios HTTP/1.1
-- OUTROS PARAMETROS OMITIDOS --
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
-- OUTROS PARAMETROS OMITIDOS --
[{"Codigo":1,"Email":"usuario1@servidor.com.br","Nome":"Nome do Usuario 1"},{"Codigo":2,"Email":"usuario2@servidor.com.br","Nome":"Nome do Usuario 2"},{"Codigo":3,"Email":"usuario3@servidor.com.br","Nome":"Nome do Usuario 3"},{"Codigo":4,"Email":"usuario4@servidor.com.br","Nome":"Nome do Usuario 4"}]
[ Operação Adicionar]
POST http://localhost/Services/ServicoDeUsuarios.svc/Adicionar HTTP/1.1
Content-Type: application/json
-- OUTROS PARAMETROS OMITIDOS --
{"Codigo":123,"Nome":"Israel","Email":"ia@israelaece.com"}
Note que a URL de requisição também contempla o método a ser disparado do lado do serviço. Os parâmetros de entrada são serializados em JSON, e o resultado idem. Na operação RecuperarUsuario, configuramos ela para que o resultado seja Wrapped, e com isso, o corpo da mensagem de retorno veio envolvida em um objeto com o nome de RecuperarUsuarioResult, ao contrário daquelas definidas como Bare, onde a requisição/resposta não estão envolvidas neste elemento adicional.
Além dos detalhes que são necessários em nível de contrato, precisamos nos atentar em como hospedar esse serviço. Você precisa configurar o endpoint do WCF para utilizar um binding exclusivo para este cenário, que é o WebHttpBinding. Se você estiver hospedando no IIS (como é o caso do exemplo acima), então provavelmente haverá um arquivo com extensão *.svc que representa o serviço. É dentro deste arquivo que precisamos trocar o "fábrica" de hosts, que deve apontar para o WebServiceHostFactory, assim como já mostrei neste artigo.
Depois de todo o serviço WCF já devidamente criado e rodando, precisamos entender a API do jQuery para consumir esse serviço de exemplo. Nos dois tipos de projetos ASP.NET (WebForms e MVC), ambos já trazem o JQuery referenciado, o que nos permite acessar o que ele fornece para consumir serviços, escritos em qualquer tecnologia. Sendo assim, o primeiro passo importante para acessar qualquer um dos recursos fornecidos pelo jQuery, devemos adicionar uma referência para o arquivo *.js correspondente ao mesmo, e para isso, podemos utilizar o seguinte elemento:
<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
Depois deste arquivo referenciado, então já podemos utilizar a API do jQuery para consumir serviços WCF. Vamos utilizar neste exemplo a função $.ajax, que é uma função de baixo nível do jQuery, e que nos permite customizar, através de uma série de parâmetros, as configurações para controlar como a mensagem será enviada e como a resposta será processada.
Entre os vários parâmetros, temos o type, que determina com a requisição será enviada ao serviço, podendo ser através de GET ou POST. A propriedade url determina o endereço até o serviço, incluindo o nome da operação a ser invocada. contentType é onde definimos como o corpo da mensagem está formatada, e apesar do jQuery utilizar um tipo genérico, que pode ser aplicado em grande parte dos casos, é sempre melhor deixar isso explícito com o tipo que você está operando. A propriedade data determina o que vai ser enviado para a operação. Essa propriedade trabalha em conjunto com uma outra propriedade chamada processData. Quando você define os dados a serem enviados para o serviço através do método GET, então os dados serão convertidos em query strings, e a propriedade processData previne esse comportamento.
Além dessas propriedades, temos algumas opções para a configuração de callbacks para alguns cenários. beforeSend permite efetuar algum processamento momentos antes da requisição ser enviada ao serviço. A opção success permite especificarmos um callback apontando para um método que deverá ser disparado quando o resultado voltar com sucesso. Já error também permite especificarmos um método a ser disparado quando algum problema acontecer no serviço. É importante dizer aqui que o tratamento de erro não será tão simples, pois o WCF não traduz automaticamente a exceção em um erro no formato JSON, o que dificulta para mostrar a mensagem de erro. Finalmente, temosum callback chamado de complete, que como o próprio nome diz, é disparado quando a requisição é finalizada, independemtente se ocorreu ou não alguma exceção durante o seu processamento.
Abaixo temos como podemos configurar a função $.ajax para executarmos a primeira operação fornecida pelo serviço WCF que criamos anteriormente, que é a RecuperarUsuario. Como o acesso deve ser feito através do método POST, então os parâmetros serão enviados no corpo da mensagem, em formato JSON. Do lado do serviço, o WCF consegue interpretar o objeto JSON que foi enviado, extrair cada propriedade e preencher cada um dos parâmetrosexigidos pela operação.
function RecuperarUsuario() {
$.ajax(
{
type: "POST",
url: "http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuario",
contentType: "application/json",
data: "{ "nome": "Israel", "email": "ia@israelaece.com" }",
processData: false,
success:
function (resultado) {
alert(resultado.RecuperarUsuarioResult.Nome);
alert(resultado.RecuperarUsuarioResult.Email);
},
error:
function (xhr, textStatus, errorThrown) {
alert("Algum Problema Ocorreu!");
}
});
}
É importante perceber que configuramos (no contrato) o corpo da mensagem para o método RecuperarUsuario como Wrapped, e que isso nos obrigará a acessar o resultado através do objeto que envolve as propriedades do usuário, e que é criada automaticamente pelo JSON, que neste caso é chamada de RecuperarUsuarioResult.
Já a segunda operação exposta pelo serviço WCF, que retorna uma coleção de usuários, vamos acessá-la através do método GET, e ao receber o resultado, vamos iterar pela coleção, acessando elemento a elemento mostrando as propriedades Nome e Email de cada usuário retornado pelo serviço. É importante perceber aqui que estamos acessando diretamente as propriedades, sem passar por aquele elemento que é gerado pelo JSON. Isso se deve ao fato de termos configurado a respectiva operação como Bare, que evita envolver o resultado neste membro extra.
function RecuperarUsuarios() {
$.ajax(
{
type: "GET",
url: "http://localhost/Services/ServicoDeUsuarios.svc/RecuperarUsuarios",
success:
function (usuarios) {
$.each(usuarios, function (indice, usuario) {
alert(usuario.Nome + ": " + usuario.Email);
})
}
});
}
Finalmente temos o método AdicionarUsuario, que recebe como parâmetro a instância da classe Usuario e o adiciona em algum repositório. O usuário é criado utilizando a sintaxe JSON, onde configuramos cada propriedade e seu respectivo valor através de uma espécie de dicionário. Só que o jQuery não traz nativamente funções para representar o objeto em formato de string, algo que é necessário para enviá-lo até o serviço. Ao invés de fazer todo o trabalho árduo para essa transformação, podemos recorrer à uma biblioteca fornecida através do site oficial do JSON, chamada de JSON2.js. Essa biblioteca fornece dois métodos para a manipulação do JSON, sendo eles: parse e stringify. O método parse retorna o objeto devidamente reconstruído a partir de uma estruturaJSON, enquanto o método stringify retorna uma string contendo representação JSON de um determinado objeto. É justamente o resultado deste segundo método que estamos enviando ao serviço:
function AdicionarUsuario() {
var usuario = { "Codigo": 123, "Nome": "Israel", "Email": "ia@israelaece.com" };
$.ajax(
{
type: "POST",
url: "http://localhost/Services/ServicoDeUsuarios.svc/Adicionar",
contentType: "application/json",
data: JSON.stringify(usuario),
processData: false,
success:
function (resultado) {
alert("Usuário adicionado com sucesso.");
}
});
}
Apenas atente-se que para este código funcionar, precisamos fazer o download do arquivojson2.js e referenciá-lo na página, como vemos abaixo:
<script src="Scripts/json2.js" type="text/javascript"></script>
Conclusão: Consumir serviços a partir de AJAX pode tornar a experiência do usuário muito melhor, já que evita a necessidade de ter efetuar a atualização completa da página. Isso já era uma necessidade, mas o jQuery torna isso muito mais simples, onde mesmo utilizando funções de baixo nível como vimos aqui, a tarefa acaba sendo muito mais simples de se realizar.