Consumindo um webservice ASP.NET com Jquery/JSON.

4 de March de 2008

Vamos começar analisando o lado do servidor, quando você consulta um WebService ASP.NET, obtém como resposta um documento XML. Para quem já utilizou o JSON sabe que além de ser mais leve, ele também é muito mais fácil de trabalhar no lado do cliente (javascript). Isso acontece por que quando o JSON é consumido pelo javascript, ele é automaticamente transformado em um objeto, assim podemos acessar as propriedades dele diretamente, sem a necessidade de navegar pelo XML. Com o lançamento do ASP.NET AJAX foi incluída a capacidade do webservice responder JSON, só que para isso é necessário fazer algumas configurações, e é sobre elas que vou falar neste artigo.

Quem já está utilizando o framework 3.5 pode ir direto para a criação do WebService.

Quem ainda está utilizando o framework 2.0, é necessário fazer a instalação do ASP.NET AJAX Extensions 1.0. Depois de instalado você terá que mudar o seu web.config, ou, ao criar o Web Site definir o template como “ASP.NET AJAX-Enabled Web Site”. Se você escolher esta opção não precisará fazer nenhuma alteração no web.config, se você já tem um projeto criado e quer acrescentar a funcionalidade nele, deverá fazer as alterações descritas neste exemplo do web.config com comentários ou copiar o exemplo abaixo:

web.config (para o frameword 2.0):

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
      <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication"/>
        <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
          <section name="JSONSerialization" type="System.Web.Configuration.ScriptingJSONSerializationSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="Everywhere" />
          <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
          <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" allowDefinition="MachineToApplication" />
        </sectionGroup>
      </sectionGroup>
    </sectionGroup>
  </configSections>

  <system.web>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </controls>
    </pages>
    <!--
          Set compilation debug="true" to insert debugging
          symbols into the compiled page. Because this
          affects performance, set this value to true only
          during development.
    -->
    <compilation debug="false">
      <assemblies>
        <add assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </assemblies>
    </compilation>

    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
    </httpHandlers>

    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </httpModules>
  </system.web>

  <system.web.extensions>
    <scripting>
      <webServices>
      <!-- Uncomment this line to customize maxJSONLength and add a custom converter -->
      <!--
      <JSONSerialization maxJSONLength="500">
        <converters>
          <add name="ConvertMe" type="Acme.SubAcme.ConvertMeTypeConverter"/>
        </converters>
      </JSONSerialization>
      -->
      <!-- Uncomment this line to enable the authentication service. Include requireSSL="true" if appropriate. -->
      <!--
        <authenticationService enabled="true" requireSSL = "true|false"/>
      -->

      <!-- Uncomment these lines to enable the profile service. To allow profile properties to be retrieved
           and modified in ASP.NET AJAX applications, you need to add each property name to the readAccessProperties and
           writeAccessProperties attributes. -->
      <!--
      <profileService enabled="true"
                      readAccessProperties="propertyname1,propertyname2"
                      writeAccessProperties="propertyname1,propertyname2" />
      -->
      </webServices>
      <!--
      <scriptResourceHandler enableCompression="true" enableCaching="true" />
      -->
    </scripting>
  </system.web.extensions>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated" />
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode"
           type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode"
           type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </handlers>
  </system.webServer>
</configuration>

Agora você deve incluir um novo WebService no seu projeto, para seguir o exemplo utilize o nome WebService.asmx. Agora vamos defini-lo como um ScriptService que contém ScriptMethods, para isso você deverá:

Veja o código do webService.cs abaixo:

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;

/// <summary>
/// Summary description for WebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class WebService : System.Web.Services.WebService {
    [WebMethod]
    [ScriptMethod(ResponseFormat=ResponseFormat.Json)]
     public string HelloWorld() {
        return "Hello World";
    }
}

O seu WebService já está preparado para responder JSON, só que não adianta abrir o browser e testar, se você fizer isto terá como resposta um documento XML, isso acontece porque para ele devolver uma resposta do tipo JSON, ele deve receber uma requisição com o “content-type=’JSON’”, senão ele devolve XML, então para testar teremos que fazer uma requisição via javascript, para fazer este teste será necessário baixar a última versão do Jquery, e um plugin (que ainda está em construção mas já funciona) que fará a chamada do webservice. Coloque estes dois arquivos na mesma pasta e não esqueça de fazer a referência no HTML.

Adicione um novo arquivo chamado JqueryComWs.aspx e copie o código abaixo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Consulta um webService</title>
    <script src="jquery-1.2.3.js" type="text/javascript"></script>
    <script src="jquery.ws.js" type="text/javascript"></script>
    <script src="meuscript.js" type="text/javascript"></script>

</head>
<body>
    <form id="form1" runat="server">
    <button id="btnHelloWorld">Helo World</button>
    <div>

    </div>
    </form>
</body>
</html>

Criar o arquivo meuscript.js na mesma pasta do arquivo aspx e digitar o código a seguir:

//Utilizando e evento de carregamento da página
$(document).ready(function(){
    //Ao clicar no botão btnHelloWorld
    $("#btnHelloWorld").click(function(){
        //Chame o WebService
        $.ws("WebService.asmx/HelloWorld",retorno);
    });
});

function retorno(JSON){
    alert(JSON);
    //para o framework 3.5 troque a linha de cima pela linha abaixo,
    //quando o webservice retorna string o parser cria um objeto "d".
    //alert(JSON.d);
}

Ao executar a página você verá que a página faz a consulta ao WebService e trás a informação que queremos, o “Hello World”.

Vamos partir para um exemplo mais complexo, passando parâmetro para o WebService
Parece que tudo está certo e terminado? Não fique tão animado! Ainda faltam algumas considerações, este teste que fizemos não passa nenhum parâmetro para o webservice, se você tentar passar parâmetro no padrão do jquery ({’chave’:'valor’,'chave’:'valor’} ou “chave=valor&chave=valor”) utilizando o “method=post” irá receber o erro “JSON primitive invalid”, isto ocorre porque (felizmente) o webservice está esperando uma string no padrão JSON, e não alguns pares de chave e valor, e é isso que o jquery passa para o webservice quando passamos parâmetros para a função ajax. Para resolver isso é só criar uma string no formato JSON e passar para ela como um único parâmetro.

Para quem ainda não percebeu, isto é muito bom, porque é possível fazer o mesmo que uma requisição soap comum, ou seja, passar objetos complexos como arrays. Vamos fazer um teste, primeiro vamos criar um novo WebService com o nome WebService2.asxm com 2 métodos:

A intenção deste exemplo é mostrar que podemos receber e enviar tipos complexos como um objeto, um array ou um array de objetos.

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.ObjectModel;
using System.Web.Script.Services;

/// <summary>
/// Definindo uma classe pessoa, para demonstrar o retorno de um objeto complexo.
/// </summary>
public class Pessoa
{
    //Construtor
    public Pessoa(){}
    public Pessoa(int Id, string Nome)
    {
        this.Nome = Nome;
        this.Id = Id;
    }
    //propriedades
    public int Id;
    public string Nome;

}

/// <summary>
/// WebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService] //aqui estamos definindo que o WebService irá se comportar como um ScriptService
public class WebService2 : System.Web.Services.WebService {
    //declarando uma propriedade privada para conter o objeto pessoas,
    //isto está sendo feito para não acessarmos um banco de dados,
    //que tornaria o exemplo mais complexo que o necessário.
    private Collection<Pessoa> pessoas;

    //método construtor do WebService, iremos utilizar ele para carregar os valores
    public WebService2 () {
       this.pessoas = new Collection<Pessoa>();
        pessoas.Add(new Pessoa(1, "Victor"));
        pessoas.Add(new Pessoa(2, "Mariana"));
        pessoas.Add(new Pessoa(3, "Valdir"));
        pessoas.Add(new Pessoa(4, "Valmir"));
        pessoas.Add(new Pessoa(5, "Alan"));
        pessoas.Add(new Pessoa(6, "Venceslau"));
        pessoas.Add(new Pessoa(7, "Daniel"));
    }

    [WebMethod]
    //definindo que WebMethod irá se comportar como um ScriptMethod que retorna JSON
    [ScriptMethod(ResponseFormat=ResponseFormat.Json)]
    public Collection<Pessoa> getPessoas() {
        //retornando o objeto pessoas que foi carregado no construtor do WebService
        return pessoas;
    }
    [WebMethod]
    //definindo que WebMethod irá se comportar como um ScriptMethod que retorna JSON
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public string setPessoasEscolhidas(int[] idPessoas)
    {
        //retornando número de pessoas que foi passdo no array idPessoas.
        return "Recebi " + idPessoas.Length + " pessoa(s).";
    }

}

Agora vamos alterar a página e o javascript para que ele passe os parâmetros corretamente:

Arquivo JqueryComWs.aspx:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Consulta um webService</title>
    <script src="jquery-1.2.3.js" type="text/javascript"></script>
    <script src="jquery.ws.js" type="text/javascript"></script>
    <script src="meuscript.js" type="text/javascript"></script>

</head>
<body>
    <form id="form1" runat="server">
    <button id="btnHelloWorld">Helo World</button>
    <div>
        <!--Definindo novos elementos que serão utilizados pelo javascript-->
        <button id="carregarPessoas">Carregar</button>
        <fieldset id="pessoas">
           <button id="enviaPessoas">Envia</button>
        </fieldset>
        <!--Fim das alterações-->
    </div>
    </form>
</body>
</html>

Arquivo meuscrip.js

//Utilizando e evento de carregamento da página
$(document).ready(function(){
    //Ao clicar no botão btnHelloWorld
    $("#btnHelloWorld").click(function(){
        //Chamar o WebService
        $.ws("WebService.asmx/HelloWorld",retorno);
        //é utilizado para o formulário não dar um post
        return false;
    });
    //vamos esconder o fieldset que irá conter as pessoas
    $("#pessoas").hide();
    //adicionando uma função ao evento click do botão carregarPessoas
    $("#carregarPessoas").click(function(){
        //chamando o método getPessoas do WebService2.asmx, quando terminar irá chamar a função retornoPessoas
        $.ws("WebService2.asmx/getPessoas",retornoPessoas);
        //é utilizado para o formulário não dar um post
        return false;
    })
    //adicionando uma função ao evento click do botão enviaPessoas
    $("#enviaPessoas").click(function(){
        //criando um array
        var intPessoas = new Array()
        //Para cada item checado dentro do fildset pessoas
        $("#pessoas :checked").each(function(i){
            //adicione o valor no array intPessoas
            intPessoas[i] = $(this).val();
        });
        //criando a string JSON que será passada como parrâmetro para o método
        //ele deverá ficar parecido com {'idPessoas':[1,4,6,8]}onde o idPessoas é o
        //nome do parâmetro e o [1,4,6,8] é o array no formato JSON
        var strPessoas ="{'idPessoas':["+intPessoas.join(",")+"]}";
        //chamando o método setPessoasEscolhidas do WebService2.asmx, quando terminar
        //irá chamar a função retornoEnviaPessoas, ele está passando como parâmetro a strPessoas
        $.ws("WebService2.asmx/setPessoasEscolhidas",retornoEnviaPessoas,strPe ssoas);
        //é utilizado para o formulário não dar um post
        return false;
    });
});

//função de retorno
function retorno(JSON){
    //dá um alert do conteúdo retornado
    //no framework 3.5 troque o JSON por JSON.d
    alert(JSON);
}

//função de retorno que exibirá as pessoas
function retornoPessoas(JSON){
    //Exibe o fieldset pessoas
    $("#pessoas").show();
    //para cada objeto retornado no JSON
    //no framework 3.5 troque o JSON por JSON.d
    $(JSON).each(function(i){
        //adione um checkbox dentro do fieldset pessoas
        $("#pessoas").prepend("<input type='checkbox' value='"+this.Id+"' id='chk_"+i+"' name='pessoa' /><label for='chk_"+i+"'> "+this.Nome+"</label><br />")
    });
}
//função de retorno que exibirá a quantidade de pessoas enviadas para o webservice
function retornoEnviaPessoas(JSON){
    //dá um alert do conteúdo retornado
    //no framework 3.5 troque o JSON por JSON.d
    alert(JSON);
}
Conclusão

Para quem precisa consumir um webservice ASP.NET com javascript e não quer utilizar a parte cliente do AJAX.NET o Jquery é uma ótima alternativa, não é necessário fazer muita coisa para deixar ele funcionando em perfeita harmonia com o .NET.

Downloads:

E-book sobre expressões regulares.

17 de February de 2007

Vi no site Inside.Web.Dev um post que apontava para um e-book que foi escrito por Aurélio Marinho Jargas e editado pela novatec.

Deu uma lida rápida e achei muito interessante, principalmente por ser um assunto que você não encontra com falcilidade em portugês.

Boa leitura.

Framework Javascript da Adobe

15 de February de 2007

Agora virou mania, todo mundo tá criando framework Javascript, achei o Spry framework for Ajax da Adobe achei ele um pouco diferente dos outros, me lembrou muito a programação em Flex da propria adobe(salvo as devidas proporções).

No próprio site tem link para documentação e para vários exemplos, entre eles:

  • Galeria de fotos — Uma galeria de fotos baseada em XML.
  • Tabela de produtos — Uma tabela interativa mostrando dados em XML.
  • Leitor RSS — Um leitor RSS com uma interface bem interessante.
  • Demo de efeitos — Vários exemplos de efeitos.
  • Vale a pena dar uma olhada.

    Tableless lança “Comunidade”!

    15 de February de 2007

    O site tableless acabou de lançar uma nova área em seu site, esta área denominada “comunidade” visa agrupar notícias de vários sites que falam sobre a mesma coisa: WEB.

    O interessante é que estas notícias serão como as que eu público neste site, são de pessoas que gostam de falar sobre WEB. Acho a idéia interessante, estou apostando nela.

    Menu com Jquery

    14 de February de 2007

    Ultimamente estou estudando o Jquery, e cada vez mais fico impressionado com a sua simplicidade, neste post vou construir um menu do tipo accordion.

    Iniciaremos construindo um XHTML semântico, eu costumo dizer em aula “todo menu é uma lista”, então criaremos uma lista

    <div id="menu">
      <ul><li>
        <a href="#1" href="#1">Menu 1</a>
        <ul><li>
          <a href="#1-1" href="#1-1" title="SubMenu 1-1">SubMenu 1-1</a></li><li>
          <a href="#1-2" href="#1-2" title="SubMenu 1-2">SubMenu 1-2</a></li><li>
          <a href="#1-3" href="#1-3" title="SubMenu 1-3">SubMenu 1-3</a></li>
        </ul></li><li>
        <a href="#1" href="#1">Menu 2</a>
        <ul><li>
          <a href="#2-1" href="#2-1" title="SubMenu 2-1">SubMenu 2-1</a></li><li>
          <a href="#2-2" href="#2-2" title="SubMenu 2-2">SubMenu 2-2</a></li><li>
          <a href="#2-3" href="#2-3" title="SubMenu 2-3">SubMenu 2-3</a></li><li>
          <a href="#2-4" href="#2-4" title="SubMenu 2-4">SubMenu 2-4</a></li><li>
          <a href="#2-5" href="#2-5" title="SubMenu 2-5">SubMenu 2-5</a></li><li>
          <a href="#2-6" href="#2-6" title="SubMenu 2-6">SubMenu 2-6</a></li>
        </ul></li><li>
        <a href="#1" href="#1">Menu 3</a>
        <ul><li>
          <a href="#3-1" href="#3-1" title="SubMenu 3-1">SubMenu 3-1</a></li><li>
          <a href="#3-2" href="#3-2" title="SubMenu 3-2">SubMenu 3-2</a></li><li>
          <a href="#3-3" href="#3-3" title="SubMenu 3-3">SubMenu 3-3</a></li>
        </ul></li>
      </ul>
    </div>
    

    Exemplo Online

    Percebam que este menu é simplesmente uma lista com sub listas.

    Agora vamos adicionar o código para fazer o efeito do accordion:

      $(document).ready(function(){
        //adicionando o evento click a todos os links que estão na primeira ul dentro da div menu
          $('#menu').find('ul:eq(0)> li > a').click(function(){
          //adicionando o efeito ao elemento ul que está dentro da mesma li do link que foi clicado
          $(this).parent().find('ul:eq(0)').slideToggle("slow");
        });
      });
    

    Exemplo Online

    Neste ponto já temos o menu funcionando, agora vamos adicionar um pouco de css:

    #menu{
    width:10em;
    font-family:Verdana, Arial, Helvetica, sans-serif;
    font-size:0.8em;
    }
    #menu a{
    text-decoration:none;
    display:block;
    }
    #menu ul{
    margin:0px;
    padding:0px;
    }
    #menu ul a{
    background-color:#ff0000;
    color:#FFFFFF;
    }
    #menu ul ul a{
    background-color:#FFFFCC;
    color:#999999;
    }
    #menu ul ul{
    display:none;
    }
    

    Exemplo Online

    Este exemplo demostra como é fácil tabalhar com o Jquery, a forma de selecinar os elementos é muito semelhante ao css, só que com alguns recursos a mais, irei explicar isto em outro post.

    «

    Busca

    Arquivos

    Categorias

    Meta

    Estilos

    Copyright - 2002-2005 - Victor Cavalcante