LuizTools 2.0

Desde 2010 codificando minhas ideias!

ASP.NET Button não dispara postback

Outros nomes possíveis para este post seriam "ASP.NET Button não funciona" ou "Que m**** que está ac

Outros nomes possíveis para este post seriam "ASP.NET Button não funciona" ou "Que m**** que está acontecendo com meu formulário?". De qualquer forma, este post será bem rápido. O objetivo é listar algumas causas comuns que fazem com que botões parem de funcionar com ASP.NET Webforms. Não há nenhuma mágica ou bug conhecido, apenas falta de atenção ou prática com a construção de formulário com este padrão de desenvolvimento web da plataforma .NET. Acredito que este post será vivo, ou seja, irei colocando mais conteúdo conforme for descobrindo mais causas para este problema.

O Problema

O problema é simples e objetivo: você tem um formulário ASP.NET com um botão. Você clica no botão e o que deveria acontecer não acontece. Claro, tem algumas variações, que podemos chamar de sintomas. Para cada sintoma, há um remédio diferente.

A tela apresenta um erro

Se a tela apresenta um erro em ASP.NET, considere-se com sorte pois geralmente os erros são muito bons em dizer onde está o problema. Alguns erros comuns incluem você estar com sua tag ASP.NET mal formada, como falta de runat="server" ou similar. Dê uma revisada nas linhas do seu .aspx ou .aspx.cs conforme mencionado no erro e acredito que não terá problemas.

Um erro comum de funcionamento de botão é quando utilizamos eles dentro de algum controle de repetição, como Repeater. Em geral os programadores esquecem que colocando o comportamento de carregar o repeater dentro do Page_Load, o mesmo será chamado toda vez acontecer algum postback, inclusive quando um botão é clicado. Por isso, é uma boa prática colocar uma verificação no Page_Load para somente carregar se não for um postback. Mas o que isso tem a ver com problemas de botão? Quando a página carrega a primeira vez e o botão é renderizado, ele possui um identificador único no ViewState, que, caso seja recarregada a tela, será alterado. Com isso, o botão que originalmente chamou o postback não existe mais e a chamada fica como se fosse anônima ou "injetada", o que é uma violação de segurança do ASP.NET que causará um erro.

A tela não apresenta erro

Aqui que mora o problema, quando estamos às cegas com um botão não funcionando. Uma dica é, usando o Google Chrome, abrir as ferramentas (F12) e ver no Console se não tem algum erro de Javascript. Isso é bem comum quando usamos UpdatePanel, que por padrão suprime os erros da página. Em geral os erros de Ajax não são muito esclarecedores, mas basta executar tudo novamente com F5, para depurar, que se acontecer o erro novamente o depurador do Visual Studio vai te levar até a linha do erro.

Às vezes o ASP.NET não apresenta erro pois de fato não existe erro. Ou seja, é algum problema de lógica ou algo Javascript seu que está bloqueando a execução do botão. Veja se seu botão não possui um OnClientClick definido, pois se caso possuir, tenha certeza de que o método Javascript associado retorna true para garantir a continuidade da execução do botão. Ainda no assunto Javascript, revise se na sua página não existe alguma tag script mal formada, lembrando que a tag script sempre deve ser fechada com o padrão "></script>" e jamais com a versão enxuta "/>", caso contrário lhe trará problemas. Sim isso é muito idiota, mas acontece, então se liga!

Um último adendo cabe aos ASP.NET Validators. Por padrão os Validators, como o RequiredFieldValidator, fazem a validação via Javascript antes de qualquer postback, e caso tenha qualquer problema em sua página impedirá que o postback aconteça. Se você usa validadores em qualquer ponto de seu formulário, pode ser uma boa verificar se não são eles que estão impedindo seu botão de funcionar. Esse ponto se torna ainda mais importante caso você esteja usando WebUserControls na sua página, pois às vezes eles estão escondidos, como em modais, mas mesmo assim com seus Validators ativos, impedindo o postback da página. Uma ideia pode ser dizer que seu botão não causa validação, definindo a propriedade CausesValidation para false. Isso claro, se o click do seu botão não for interferir com os demais dados do seu formulário.

Espero ter ajudado.

Tem mais algum caso em que seu botão não funciona e que deseja compartilhar? Outro detalhe que deixei passar? Escreva nos comentários!

Aumentando o desempenho de seus sites - Parte 2

Neste post continuo com mais dicas para melhorar a performance de sites que possuam muitas visitas.

Neste post continuo com mais dicas para melhorar a performance de sites que possuam muitas visitas. A primeira versão deste post pode ser encontrada neste link.

Carregue componentes após o load

Você deve olhar para sua página e se questionar: "O que é absolutamente necessário para que a página renderize?". O resto do conteúdo e dos componentes podem esperar.

JavaScript é um candidato ideal para ser carregado depois do evento load. Por exemplo se você tem um código JavaScript para fazer animações em botões, eles podem esperar, porque as animações só vão fazer sentido depois que toda página tiver sido renderizada. Outros locais a se dar uma olhada incluem conteúdo oculto (conteúdos que aparecem somente após alguma interação do usuário) e algumas imagens que não são visualizadas em um primeiro momento.

É bacana quando os objetivos de performance estão alinhados com as melhoras práticas web. Neste caso, a idéia de aperfeiçoamentos progressivos nos diz que Javascript, quando suportado, pode melhorar a experiência do usuário, mas você tem que ter certeza de que a página funciona mesmo sem JavaScript. Então depois que tiver certeza disso, você pode aperfeiçoar ela com alguns scripts pós-carregados que dêem mais recursos à página, como botões animados.

Carregue componentes antes do load

Pré-carregar pode ser entendido como o oposto de Pós-carregar, mas na verdade ele possui um objetivo diferente. Pré-carregar componentes lhe dá uma vantagem sobre o tempo ocioso do browser, quando ele poderia, por exemplo, estar carregando imagens que serão usadas futuramente. A idéia é quando o usuário troque de página, ele tenha uma experiência ainda mais rápida do que na primeira página.

Existem vários tipos de pré-carregamento:

  • Não-condicional: assim que o load inicia, vá em frente e carregue uns componentes extras. O site do Google utiliza esta técnica, carregando todas imagens através de CSS Sprite que serão usadas nas páginas seguintes (página de resultados, por exemplo)
  • Condicional: baseado na ação do usuário você faz um palpite do que o usuáro está pensando e já carrega os próximos componentes. O Yahoo usa esta técnica na caixa de busca deles, carregando alguns componentes conforme o que o usuário digita na caixa de busca.
  • Antecipado: esta técnica é utilizada quando você está pensando em trocar o layout do seu site em breve. Geralmente você ouve coisas do tipo "Muito legal o novo site do fulano, mas o antigo era mais rápido.". Isso acontece porque o site antigo já estava com os elementos em cache, como imagens, JS e CSS, enquanto que no novo site tudo teve de ser baixado. O pré-carregamento antecipado consiste em fazer com que seus visitantes do site antigo já baixem alguns componentes e deixem-os em cache no navegador, para quando o novo site for pro ar, a transição seja mais suave. Faça isso linkando CSS e JS antecipados, alguns dias antes do lançamento. Colocar algumas imagens sobrepostas também pode ajudar.

Divida componentes entre domínios

Dividir os componentes entre domínios pode maximizar o download paralelo de componentes. Garanta que não está usando mais do que 2-4 domínios por causa do tempo de resolução de DNS ou a técnica sairá pela culatra. Por exemplo, você pode hospedar seu HTML e conteúdo dinâmico em www.teste.com.br e dividir componentes estáticos ente img.teste.com.br e css-js.teste.com.br.

Fora 404!

Requisições HTTP são recursos "caros" à performance de um site o que torna uma imensa burrice permitir erros 404 em seu site por preguiça ou ignorância.

Alguns sites possuem páginas 404 bacanas que ajudam o usuário a encontrar o que não acharam na URL acessada, entretanto, mesmo estas páginas consomem recursos do servidor. Pior ainda é quando os erros 404 são causados por links de JS e CSS quebrados. No primeiro caso, além de gerar uma custosa requisição, o carregamento do restante da página irá travar até que o referido erro aconteça porque o download de javascript não permite outros downloads em paralelo. Como se não fosse o bastante, muitos browsers tentarão ler a página 404 procurando algum script útil pois buscavam um arquivo de scripts...

Use link ao invés de @import

Uma das melhores práticas que citei na parte 1 deste post dizia que CSS deve estar no topo da página para permitir a renderização progressiva. No IE a diretiva @import tem o mesmo comportamento que usar um <link> no rodapé da página, então é melhor não usá-la.

Otimize as imagens

Depois que o designer tenha terminado de criar as imagens para sua página, existem ainda algumas coisas que você pode fazer antes de enviar as imagens para seu servidor.

  • você pode verificar os GIFs e ver se eles estão usando um tamanho de palheta correspondente ao número de cores na imagem. Usando o software ImageMagick é fácil de verificar com o comando: identify -verbose imagem.gif. Quando você ver que uma imagem está usando 4 cores e uma palheta de 256 cores, há espaço para melhoria.
  • Tente converter GIFs para PNGs e ver se há alguma economia. Geralmente tem. Desenvolvedores muitas vezes hesitam em usar PNGs devido ao suporte limitado nos browsers, mas isto é coisa do passado. O único problema real é a transparência-alfa em PNGs true color, mas novamente, GIFs não são true color e não suportam transparência variável. Então qualquer coisa que um GIF possa fazer um PNG também faz (exceto animações). Este simples comando do ImageMagick gera PNGs seguros para usar: convert image.gif image.png
  • Execute o aplicativo pngcrush (ou qualquer outro otmizador de PNG) em todos seus PNGs, por exemplo, com este comando: pngcrush imagem.png -rem alla -reduce -brute resultado.png
  • Execute o aplicativo jpegtran em todos seus JPEGs. Esta ferramenta faz operações sem perdas em JPEGs como rotação e também pode ser usada para otimizar e remover comentários e outras informações inúteis (como informações EXIF) em suas imagens. Ex: jpegtran -copy none -optimize -perfect imagem.jpg destino.jpg

Otimize seus CSS Sprites

Aqui vão algumas dicas que deixarão seus sprites ainda mais otimizados:

  • organizar as imagens no sprite horizontalmente ao invés de verticalmente resultará em arquivos menores
  • combinar cores similares em uma sprite lhe ajuda a manter a contagem de cores baixa, idealmente abaixo de 256 cores para que se encaixe em um arquivo PNG8.
  • não deixe grandes espaços entre as imagens do sprite. Isto não afeta muito o tamanho do arquivo mas requer menos memória do usuário para descomprimir a imagem em um mapa de pixels. Uma imagem 100x100 tem 10 mil pixels, enquanto uma 1000x1000 tem um milhão

Não escale as imagens no HTML

Não use uma imagem grande que você precise definir a largura e altura dela em HTML. Se você precisar fazer isso:
<img width="100" height="100" src="meucachorro.jpg" alt="Meu Cachorro" />
então sua imagem (meucachorro.jpg) deve ter o tamanho de 100x100px ao invés redimensionar uma imagem de 500x500px, por exemplo.

Mantenha seus componentes abaixo de 25K

Esta restrição está relacionada ao fato que o iPhone não faz cache de componentes maiores que 25K. Note que este é o tamanho não comprimido. Isto é um exemplo de onde a minificação é importante porque o gzip sozinho pode não ser suficiente. Para mais informações, busque por iPhone Cacheability no Google.

Evite imagens com Src vazio

Imagens com o atributo src vazio provocam requisições ao seu servidor, em busca das imagens. Independente da forma que você fez isso:

<img src="">

ou

var img = new Image();
img.src = "";

Por quê este comportamento é ruim? Simplesmente porque lota seus servidores enviando um monte de tráfego inesperado, especialmente em páginas que recebem milhões de pages views por dia. Como se isso não fosse o bastante, você gasta tempo de processamento gerando páginas que não serão visualizadas. E por último, mas não menos importante, você pode acabar corrompendo dados. Se você está rastreando estado na requisição, seja por cookies ou de outra forma, você tem a possibilidade de destruir esses dados. Isso porque a requisição de imagem não retorna uma imagem, todos os cabeçalhos são lidos e aceitos pelo browser, incluindo todos cookies. Enquanto que o resto da resposta é jogada fora, o dano já pode ter sido feito.

A causa raiz deste comportamento é que a resolução de URLs dos browsers é definida na RFC 3986 - Uniform Resource Identifiers. Quando uma string vazia é encontrada como uma URI, ela é considerada uma URI relativa e é resolvida de acordo. Então tecnicamente, os browsers estão fazendo o que é esperado que façam para resolver URLs relativas. O problema é que neste contexto, a string vazia é claramente intencional.

HTML5 adiciona à RFC instruções aos browsers não fazerem requisições adicionais. Espera-se que em um futuro próximo não tenhamos mais esse problema, embora a RFC não cubra <script src=""> and <link href="">.

Conclusões

Neste post continuei um post muito antigo sobre dicas de otimização de sites. Muitas delas aplico em projetos que participo e que atinjam milhares de visitantes por dia, como o Busca Acelerada que possui mais de 240mil page-views por mês. Estas dicas foram retiradas de diversas fontes da Internet, em especial das guidelines de performance do Yahoo e de palestras que assisti sobre o assunto em diversos eventos pelo país. Em um post futuro, quero dar dicas específicas para desenvolvedores ASP.NET, sobre como turbinar suas web applications. Então aguardem!

Relançamento do Busca Acelerada

Meu antigo projeto, Busca Acelerada, volta com for&#231;a total para facilitar a vida de quem est&#225; em busca de seu novo carro.

Busca Acelerada

Boa noite pessoal. Hoje o post na verdade é um jabá descarado de um antigo projeto que só agora foi voltar ao ar: o Busca Acelerada (http://www.buscaacelerada.com.br).

Se eu tivesse que resumir do que se trata o site eu diria que é "O Google dos carros.". Ok, é uma analogia meio pretensiosa mas é basicamente isso mesmo. A ideia é que as pessoas não tenham mais que entrar em diversos sites de anúncios de carros para encontrar o veículo que procuram. Você entra no Busca Acelerada, digita os termos que definem o carro que busca (marca, modelo, etc) e o Busca Acelerada lhe traz o resultado de dezenas de sites de classificados, em milésimos de segundo e com possibilidades de filtrar os resultados, ordenar, etc.

Por enquanto o projeto está em testes (beta) e somente está englobando os cerca de 5700 anúncios de veículos da cidade de Gravataí-RS (a minha). Ainda assim, eu gostaria que acessassem e dessem um feedback, seja aqui pelo blog, pela página do facebook (http://www.facebook.com/BuscaAcelerada). Em breve estarei, em conjunto de meus sócios Lucas Pfeiffer e Adriano Costa, expandindo o sistema para todo RS e posteriormente para todo Brasil. Então mesmo que não seja Gravataiense como eu, me ajude a construir a melhor ferramenta de busca de veículos do país.

Valeu!