jQuery + Ajax + ASP.NET Generic Handler = Interactividade e Performance

Written by Bruno Pires on Agosto 23rd, 2010

jquery-logo

O título pode parecer demasiado confuso com a utilização de tantos termos, no entanto estou confiante que no fim do artigo, vai estar de acordo com a escolha.

Recentemente deparei-me com uma nova situação, por um lado necessitava de toda a interactividade e flexibilidade proporcionada pelo jQuery no cliente mas também queria continuar a utilizar no lado do servidor Microsoft ASP.NET de forma convencional, ou seja, eu precisava do melhor dos dois mundos.

Depois de executar alguns testes, encontrei rapidamente alguns entraves, limitações e complexidades, o que me levou à procura de uma solução simples e  eficaz.

Deparei-me com um cenário em que o utilizador necessitava de preencher um formulário extenso, para tornar mais agradável a experiência do utilizador, para isso implementei vários plugins do jQueryUI, conforme se pode verificar nas imagens em baixo.

 

img_6

img_7

img_8

 

A informação a inserir é extensa e necessita de validação no lado do servidor, não se torna prático executar tudo isso postback atrás de postback até estar tudo correcto, utilizar update panels torna-se demasiado complexo para o tipo de validação necessário e a biblioteca Ajax do ASP.NET não é das mais agradáveis de utilizar quando necessitamos de performance, optei por isso experimentar utilizar o método Ajax disponibilizado pelo jQuery.

Para simplificar o artigo, e porque o que realmente interessa é o conceito, optei por criar um formulário de teste cujo objectivo é adicionar um cliente ao sistema.

img_9

 

Depois adiciona-se um novo item ao projecto, um Generic Handler

img_10

Visto de uma forma mais simplista, um Generic Handler é uma página ASP.NET que contém apenas um método e não suporta eventos nem controlos.

De seguida vamos adicionar um novo ficheiro JS e utilizando método Ajax da biblioteca jQuery, vai ser chamado o Generic Handler AdicionarClienteHandler.

A função Ajax é de simples implementação, como se pode verificar ao analisar o script apresentado.

$(document).ready(function () {

    //activa o plugin Tabs
    $(function () {
        $("#tabs").tabs();
    });

    //método adicionar cliente
    $('#btnAdicionar').click(function () {

        $.ajax({
            url: '../../Handlers/AdicionarClienteHandler.ashx',
            data: $('form').serialize(),
            type: 'POST',
            success: function (data) {
                alert('Cliente adicionado com sucesso.');
                $('#listClientes').append(data);
            },
            error: function (data) {
                alert("Ocorreu um erro ao processar o seu pedido.");
            }
        });
    });
});

O utilizador vai preencher o formulário e quando é executado o click sobre o botão adicionar, vai ser executado o script apresentado anteriormente.

img_1

Este script vai serializar todos os campos de input que se encontram dentro da tag <form> e enviar esta informação para o Generic Handler através de um POST executado de forma assíncrona.

img_2

 

Depois o Generic Handler vai processar a informação enviada, executar as suas validações e construir a resposta.

using System;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace WebApplication1.Handlers
{

    public class AdicionarClienteHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            var form = context.Request.Form;
            context.Response.ContentType = "text/html";
            context.Response.Write(ProcessaFormulario(form));
        }

        protected string ProcessaFormulario(NameValueCollection form)
        {
            string username, nome, email, telefone, telemovel, fax;

            nome        = form["txtNome"];
            username    = form["txtUsername"];
            email       = form["txtEmail"];
            telefone    = form["txtTelefone"];
            telemovel   = form["txtTelemovel"];
            fax         = form["txtFax"];

            var buildResponse = new StringBuilder();

            buildResponse.AppendLine("<div class=\"DefaultRow\">");
            buildResponse.AppendLine(string.Format("<h6>{0}</h6>", nome));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Username: {0}</span>", username));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Email: {0}</span>", email));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Telefone: {0}</span>", telefone));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Telemóvel: {0}</span>", telemovel));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Fax: {0}</span>", fax));
            buildResponse.AppendLine("</div>");

            return buildResponse.ToString();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

 

A resposta por sua vez, é a informação do cliente formatada de acordo com a forma pretendida e pronta para ser adicionada à lista de clientes.

img_3

img_5

Tudo isto é executado de forma assíncrona, simples, eficaz e sem a necessidade de executar qualquer postback.

 

/*Versão JSON*/

Depois de verificar que surgiram alguns pedidos relativamente à utilização de JSON na resposta do Generic Handler, deixo aqui as alterações necessárias:

using System;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Script.Serialization;

namespace WebApplication1.Handlers
{

    public class AdicionarClienteHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            var form = context.Request.Form;
            var serializer = new JavaScriptSerializer();

            context.Response.Charset = "utf-8";
            context.Response.ContentType = "application/json";
            context.Response.Write(serializer.Serialize(JsonResponse(form)));
        }

        public List<string> JsonResponse(NameValueCollection form)
        {
            string username, nome, email, telefone, telemovel, fax;

            var lista   = new List<string>();
            nome        = form["txtNome"];
            username    = form["txtUsername"];
            email       = form["txtEmail"];
            telefone    = form["txtTelefone"];
            telemovel   = form["txtTelemovel"];
            fax         = form["txtFax"];

            lista.Add(nome);
            lista.Add(username);
            lista.Add(email);
            lista.Add(telefone);
            lista.Add(telemovel);
            lista.Add(fax);

            return lista;

        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

Como podemos verificar na imagem em baixo, a resposta é agora JSON

foto_2

 

img_5

O projecto de teste aqui demonstrado , desenvolvido em Visual Studio 2010, está disponível para download aqui.

 

Referências:

http://api.jquery.com/serialize/

http://api.jquery.com/category/ajax/

http://msdn.microsoft.com/en-us/library/bb398986.aspx

 

17 Comments so far ↓

  1. Cristóvão Morgado diz:

    Uma sugestão, não devolvas HTML na resposta mas um objecto JSON, e depois faz o binding em jQuery.

    Outra seria usares serviços WCF com HTTP REST para teres mais flexibilidade

    • Bruno Pires diz:

      Cristóvão, tens toda a razão no teu comentário.

      A forma mais correcta é devolver um objecto JSON.
      É possível utilizar um WCF, um Webservice ou até decorar com [System.Web.Services.WebMethod()] um método no code-behind de uma página ASPX.

      No entanto, o principal objectivo do artigo é demonstrar de forma simples e sucinta, uma das várias implementações possíveis para resolver o problema.

      Obrigado pela tua contribuição.

    • Diego Teixeira diz:

      Boa noite.

      Cristóvao,

      Você teria um exemplo com o objeto JSON com response?

      Grato pela atenção.
      Diego Teixeira

  2. Obrigado pelo artigo Bruno

    Um erro que cometi num último projecto foi desenvolver uma plataforma muito baseada no AjaxControlToolkit e estou mais que arrependido pelo performance da aplicação, UpdatePanels para aqui e para ali, etc etc. O próximo passo é sem dúvida ir substituindo alguns componentes.

  3. Rodolfo Pereira diz:

    Obrigado pela dica, Bruno!

    Estou fazendo a migração de um CMS em ASP para ASP.NET e o seu artigo foi bastante útil para mim.

    Como ainda estou apredendo ASP.NET, gostaria de saber se possível, por que utilizar uma página .ashx ao invés de uma página .aspx normal.

    Valeu, abraço!

    • Bruno Pires diz:

      Obrigado Rodolfo.
      O ashx é um handler, enquanto que aspx é um webform. O aspx tem as funcionalidades necessárias para efectuar o rendering de uma página e o ashx não foi desenhado para esse fim.

  4. Muito bom o artigo Bruno. Segue o javascript para quem quer usar o retorno JSON:

    //método adicionar cliente
    $(‘#btnAdicionar’).click(function () {

    $.ajax({
    url: ‘../../Handlers/AdicionarClienteHandler.ashx’,
    data: $(‘form’).serialize(),
    type: ‘POST’,
    success: function (data) {

    alert(‘Cliente adicionado com sucesso.’);

    var html = ”;
    html+= ” + data[0] + ”;
    html+=’Username: ‘ + data[1] + ”;
    html+=’Email: ‘ + data[2] + ”;
    html+=’Telefone: ‘ + data[3] +”;
    html+=’Telemóvel: ‘ + data[4] + ”;
    html+=’Fax: ‘ + data[5] + ”;
    html+=”;

    $(‘#listClientes’).append(html);
    },
    error: function (data) {
    alert(“Ocorreu um erro ao processar o seu pedido.”);
    }
    });
    });

  5. Jean diz:

    Como faço para persistir estas informações em um banco de dados e atualizar um gridview

  6. Paulo diz:

    A performance é o menor dos muitos problemas do AjaxControlToolkit.
    Obrigado pelo artigo.

  7. Rodrigo diz:

    Primeiramente gostaria de agradecer pelo post que me foi muito útil.
    Só fiquei com uma dúvida, fiz exatamente como explicado e funcionou, mas no meu form eu possuo um campo checkbox, e não consigo pegar se ele está check ou não.
    Fiz isso e não está funcionando.
    Ex:
    bool restritivo = Convert.toBoolean(form["txtFax"]);

  8. Rodrigo diz:

    [txtFax] na verdade é ["restritivo"]

  9. Nei diz:

    Como faria para pegar um arquivo html e com o jquery enviar o forma para um arquivo json quando for enviado o asp.net processar ele e enviar no formato json para que um jquery no mesmo arquivo html possa ler resposta?

Leave a Comment





3 Trackbacks / Pingbacks

  1. Dica: jQuery + Ajax + ASP.NET Generic Handler = Interactividade e Performance « Fabio Stawinski
  2. Plugins Jquery | Diário da Fonte
  3. Porque usar Generic Handler? « Theodozio