Brincando com AJAX e SOAP na plataforma .NET

 

Introdução

SOAP (Simple Object Access Protocol) é um protocolo simples baseado em XML que surgiu devido à necessidade de integração de sistemas web e foi definido pelo w3c. Sua utilização independe da linguagem de programação ou plataforma.

 

Neste artigo utilizaremos SOAP na versão 1.1 para implementarmos um exemplo prático.

 

SOAP

O protocolo SOAP é um elemento XML que deve possuir elementos obrigatórios e alguns elementos opcionais.

 

Elementos obrigatórios

 

· Envelope: é a raiz da mensagem SOAP.

Exemplo:

<?xml version='1.0' encoding='utf-8'?>

<soap:Envelope

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xmlns:xsd='http://www.w3.org/2001/XMLSchema'

xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>

...

</soap:Envelope>

 

· Body: este elemento contém a mensagem SOAP propriamente dita.

Exemplo:

<?xml version='1.0' encoding='utf-8'?>

<soap:Envelope

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xmlns:xsd='http://www.w3.org/2001/XMLSchema'

xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>

<soap:Body>

     ...

</soap:Body>

</soap:Envelope>

 

Elementos opcionais

· Header: contém informações especificas da aplicação. Obs: O Header deve ser o primeiro elemento do Envelope.

Exemplo:

<?xml version='1.0' encoding='utf-8'?>

<soap:Envelope

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xmlns:xsd='http://www.w3.org/2001/XMLSchema'

xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>

<soap:Header>

     ...

</soap: Header>

<soap:Body>

     ...

</soap:Body>

</soap:Envelope>

 

· Fault: indica a ocorrência de um erro no processamento. Obs: O Fault deve estar dentro do elemento Body. O elemento Fault contém os seguintes “nós”:

 

faultcode – código do erro;

faultstring – descrição do erro;

faultactor – ator do erro;

detail – detalhes do erro.

 

Exemplo:

<?xml version='1.0' encoding='utf-8'?>

<soap:Envelope

xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'

xmlns:xsd='http://www.w3.org/2001/XMLSchema'

xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>

<soap:Header>

     ...

</soap: Header>

<soap:Body>

      <soap:Fault>

            <faultcode></faultcode>

            <faultstring></faultstring>

            <faultactor></faultactor>

            <detail></detail>

      </soap:Fault>

      ...

</soap:Body>

</soap:Envelope>

 

Criando WebService

Vamos criar um simples WebService para acessarmos via AJAX + SOAP. Não vou descrever todos o processo de criação de WebServices aqui, pois já o fiz no artigo “Acesso Assíncrono a WebServices na plataforma .NET – Parte II” (//www.devmedia.com.br/articles/viewcomp.asp?comp=5383&hl).

 

Criando métodos no WebService

Vamos criar um método chamado Somar que retorna uma string no formato XMLSOAP, afim de exemplificar o Acesso Assíncrono. Segue o código da classe:

 

using System;

using System.Web;

using System.Collections;

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml;

 

/// <summary>

/// Summary description for WebServiceArtigo

/// </summary>

[WebService(Namespace = "http://tempuri.org/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class WebServiceArtigo : System.Web.Services.WebService

{

 

    public WebServiceArtigo()

    {

        //Uncomment the following line if using designed components

        //InitializeComponent();

    }

 

    [WebMethod]

    public string HelloWorld()

    {

        return "Hello World";

    }

 

    [WebMethod]

    public int Somar(int[] p_arrParametros)

    {

        return p_arrParametros[0] + p_arrParametros[1];

    }

}

 

Como conhecer o modelo do XMLSOAP para request e response?

Existe uma forma para se saber como consumir, no caso, o método Somar do WebService criado anteriormente, basta acessar a interface do mesmo. Para isso digite o endereço local do WebService no navegador (http://localhost:1689/WebSiteArtigo/WebServiceArtigo.asmx).

 

A figura abaixo mostra a interface de acesso do WebService criado anteriormente:

 

dgbaspnfig011.jpg 

 

Na parte superior da interface, existe um link com o nome do seu método (Somar). Se clicarmos lá, abrir-se-á uma nova página com os modelos de consumo do método via SOAP 1.1, SOAP 1.2 e via HTTP POST. No nosso exemplo, utilizaremos apenas o modelo de consumo via SOAP 1.1.

 

É importante nos atentarmos para os cabeçalhos SOAPAction e Content-Type, pois os utilizaremos para realizar a requisição SOAP.

 

A figura abaixo representa a interface que contém os modelos de consumo dos métodos do nosso WebService:

 

dgbaspnfig021.jpg 

 

Agora nós já sabemos qual é o modelo do XMLSOAP de envio e retorno do método Somar.

 

JavaScript para realizar o Acesso Assíncrono

Agora colocaremos o código JavaScript utilizado para consumir o método Somar do nosso WebService. Segue o código:

 

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

 

<!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>Untitled Page</title>

    <script type="text/javascript">

        var NMHOST = "localhost:1689";

        var URLWEBSERVICE = "http://" + NMHOST +

            "/WebSiteArtigo/WebServiceArtigo.asmx";

 

        var objXMLHttpRequest;

 

        function NovoXMLHttpRequest()

        {

            if(window.XMLHttpRequest) // Mozilla, Safari...

            {

                objXMLHttpRequest = new XMLHttpRequest();

            }

            else if(window.ActiveXObject) // IE

            {

                try

                {

                    objXMLHttpRequest = new

                        ActiveXObject("Msxml2.XMLHTTP");

                }

                catch(e)

                {

                    try

                    {

                        objXMLHttpRequest = new

                            ActiveXObject("Microsoft.XMLHTTP");

                    }

                    catch(e){}

                }

            }

        }

       

        function Somar()

        {

            NovoXMLHttpRequest();

 

            objXMLHttpRequest.onreadystatechange = ProcessarResposta;

            objXMLHttpRequest.open("POST", URLWEBSERVICE, true);

            objXMLHttpRequest.setRequestHeader("SOAPAction",

                "http://tempuri.org/Somar");

            objXMLHttpRequest.setRequestHeader("Content-Type",

                "text/xml; charset=utf-8");

            objXMLHttpRequest.send(ValoresEnvio());

        }

 

        function ProcessarResposta()

        {

            if(objXMLHttpRequest.readyState == 4)

            {

                if(objXMLHttpRequest.status == 200)

                {

                    var XMLDoc = objXMLHttpRequest.responseXML;

 

                    document.getElementById("lblResultado").innerHTML =

                        XMLDoc.getElementsByTagName("SomarResult")[0].

                        childNodes[0].nodeValue;

                }

            }

        }

 

        function ValoresEnvio()

        {

            var arrParametros = new Array();

            arrParametros[0] = document.getElementById(

                "txtValor1").value;

            arrParametros[1] = document.getElementById(

                "txtValor2").value;

           

            return "<?xml version='1.0' encoding='utf-8'?>" +

                "<soap:Envelope " +

                "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " +

                "xmlns:xsd='http://www.w3.org/2001/XMLSchema' " +

                "xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>"

+

                "<soap:Body>" +

                "<Somar xmlns='http://tempuri.org/'>" +

                "<p_arrParametros>" +

                "<int>" + arrParametros[0] + "</int>" +

                "<int>" + arrParametros[1] + "</int>" +

                "</p_arrParametros>" +

                "</Somar>" +

                "</soap:Body>" +

                "</soap:Envelope>";

        }

 

        function RegistrarScript()

        {

            document.getElementById("btnSomar").onclick = new

                Function("Somar();");

        }

    </script>

</head>

<body onload="RegistrarScript();">

    <form id="form1" runat="server">

    <div>

        <asp:TextBox ID="txtValor1" runat="server"></asp:TextBox>

        <asp:TextBox ID="txtValor2" runat="server"></asp:TextBox>

        <input id="btnSomar" type="button" value="Somar" /><br />

        <asp:Label ID="lblTexto" runat="server"

            Text="Resultado:"></asp:Label>

        <asp:Label ID="lblResultado" runat="server"></asp:Label></div>

    </form>

</body>

</html>

 

O método JavaScript a ser chamado no nosso Acesso Assincrono é o Somar, que é vinculado ao botão btnSomar através do método RegistrarScript que por sua vez é chamado no evento onload da tag body, conforme mostrado no código acima.

 

Obs: É importante enfatizar que no Acesso Assíncrono com SOAP, o método setRequestHeader do objeto XMLHttpRequest dever ser setado com pelo menos dois cabeçalhos http: SOAPAction e Content-Type. Essas informações podem ser recuperadas da interface do WebService.

 

Abaixo temos a representação gráfica da interface do nosso exemplo:

 

dgbaspnfig02.jpg 

 

Finalizando

Neste artigo abordamos a construção de um exemplo prático passo-a-passo de Acesso Assíncrono com SOAP.

 

Fica um desafio para vocês (leitores): consumir o método HelloWorld com AJAX + SOAP do WebService criado neste artigo. Na verdade é uma “tarefa de casa” (risos).

 

Espero ter contribuído!

 

Até o próximo!

Diego Gazotto Dezembro