Performance em Aplicações ASP.NET

A Microsoft disponibilizou as apresentações exibidas no TechED neste link. Entre as apresentações, baixei uma chamada:

DEV411 ASP.NET: Best Practices for Performance
Speaker(s): Stephen Walther

Learn how to dramatically improve the performance of your ASP.NET applications by taking advantage of the best practices for caching and database access. Learn methods for accurately measuring the current performance of your applications and identifying performance bottlenecks. Explore a variety of application authoring techniques that will enhance the performance of your applications.
Download Powerpoint Presentation

Entre as comparações realizadas pelo autor, temos:

* DataReaders vs. DataSets
* Utilizando ArrayList em relação aos DataReaders
* OleDbDataReader vs. SqlDataReader
* InLine SQL vs. Stored Procedures
* DataReader Column Reference (Interessante)
* Proper Case vs. Improper Case (Interessante)
* InLine vs. ASP.NET Controls
* ViewState Enabled vs. ViewState Disabled (DataGrid)
* Auto Generate Columns vs. Template Columns (Interessante)

Realmente vale a pena dar uma olhada, principalmente para quem desenvolve aplicações para Web e necessitar uma boa performance (talvez isso seja essencial em qualquer software).

PostBack

Este Whidbey está realmente fantástico. Agora os controles que geram Postback tem uma propriedade chamada PostTargetUrl, qual definimos em qual página será “postado” este WebForm.

Depois nesta página que foi definida como receptora, basta fazer:

Response.Write(DirectCast(PreviousPage.FindControl(“TextBox1”), TextBox).Text)

Isso não é nada comparado ao que vem por aí.

Application Mappings

Em uma aplicação, necessitei criar um subdiretório onde nele preciso de um arquivo Web.Config que farei configurações restritas àquele diretório. Isso me forçou a fazer deste diretório um diretório de Aplicação no IIS.

Isso solucionou parte do meu problema, pois nesse caso, o diretório não “enxergava” que seus códigos de aplicação (*.dll) estavam no diretório “Bin” no mesmo nível deste novo subdiretório. Com isso, a DLL não era encontrada e o erro de não encontrar o Library ocorria.

Pois bem, depois de alguns testes, pude perceber que quando fazemos isso, temos que mapear a aplicação (arquivo *.dll) para este novo subdiretório que irá se basear neste “mapping” para executar seus respectivos códigos. Abri o IIS 6.0, fui até esse novo subdiretório da minha aplicação (qual já é um diretório de aplicação), e adicionei um “mapping” para o arquivo *.dll da aplicação que estou desenvolvendo, que está no diretório “Bin” no mesmo nível deste novo subdiretório.

O uso do JavaScript

Bem, sou um tremendo fã do Visual Studio e da plataforma .NET. Achei essa IDE bem prática, rápida e de fácil entendimento. Com o passar do tempo, cada dia mais ficamos à vontade dentro do VS.NET, e com isso, nos leva à acharmos falta de possíveis recursos que nos ajudariam muito.

Quando conheci o VS.NET pela primeira vez, achei que JavaScript “já era”, principalmente depois de ver os RequiredFieldValidators, pois usava muito a validação de formulários em ASP 3.0, e achei que todos os meus problemas estariam resolvidos.

A medida que a aplicação já está sendo testada/utilizada por usuário finais, aos poucos vamos notando a deficiencia ou a falta de recursos com relação à tratamento Client-Side. As vezes dependendo de uma escolha de um OptionButton ou CheckBox, gostaria de desabilitar algum outro controle, e utilizar AutoPostBack = True para o controle, muitas vezes não é o mais ideal, visto que o formulário é submetido, os eventos tratados Server-Side, o que torna um pouco tedioso para o usuário final.

Mesmo sabendo que o VS.NET utilizaria JavaScript para fazer tais validações (no caso do RequiredFieldValidators e os demais Validators), achei que o uso do JavaScript estaria abolido do desenvolvimento Web.

Vejo a cada dia, que o JavaScript é bastante importante no desenvolvimento de Aplicações Web, quem sabe até a versão Whidbey isso será mais fácil, ou quem sabe até uma nova versão de browser. 😉

Expirar Variáveis de Sessão

Em um projeto que estou trabalhando, o menu superior do mesmo (diferente para cada usuário, de acordo com suas permissões), está sendo armazenado em uma váriavel de sessão. Porém o problema acontece quando eu utilizo a mesma instancia do browser para entrar com usuários diferentes, ou seja, a variável de sessão é mantida, mesmo no Logout forçando com o método Session.Abandon(), a variável continuava com seu valor. Ela só atualizaria se der um Refresh (F5) na página, trazendo assim os dados corretos do usuário corrente.

A solução aqui foi utilizar a Sub Cache.SetCacheability da classe Response, definindo o HttpCacheability como NoCache na página inicial. Com isso, ele força o browser à não “cachear” a página, conseguindo assim, o resultado que estava esperando.

“Invalid CurrentPageIndex value. It must be >= 0 and < the PageCount."

Bem, tenho um DataGrid e logo acima uma TextBox onde é feito a busca na Base de Dados SQL Server e se encontrado algum registro o DataGrid é populado. Isso funciona sem problemas, mas quando avançava na paginação e tentava novamente fazer uma busca, uma Exception era disparada:

“Invalid CurrentPageIndex value. It must be >= 0 and < the PageCount.”

Depois de alguns testes e vasculhar no Google, a solução foi ao carregar o DataGrid, “setar” a Propriedade CurrentPageIndex do DataGrid para 0 (Zero).

Bom, fica aqui a dica. 😉

CausesValidation

Bem, por mais banal que seja, eu e o colega de trabalho batemos a cabeça. Tínhamos um Datagrid com um ImageButton e logo abaixo um Formulário com Validators onde se edita os dados. O que acontecia era o seguinte: Quando clicávamos no ImageButton do DataGrid a Validação era executada, que na verdade não era para acontecer, ou seja, somente no clique do botão desse formulário.

Como de costume, abri o Help e comecei a vasculhar, e lendo sobre a Sub Validate() da Page encontrei:

To disable validation for a page, or any button control on the page, set the button control’s CausesValidation property to false.”

Resumindo: Se não quiser que um determinado Button não valide a página, basta setar a propriedade CausesValidation para False. Fácil não 😐

Apagando os valores de todos os TextBox de um WebForm

Depois de muito custo, consegui fazer um código que ao executá-lo ele apaga todos os valores dos controles do tipo TextBox do WebForm. Abaixo:

Dim ctl As Control
For Each ctl In Me.FindControl(“Form1”).Controls
    If TypeOf ctl Is TextBox Then
        DirectCast(ctl, TextBox).Text = String.Empty
    End If
Next

Através de um laço For…Each percorremos a coleção de controles de um determinado WebForm e verificamos se cada controle é um tipo de TextBox. Se sim, apenas atribuímos o valor “String.Empty”, ou seja, “nada” à propriedade Text do mesmo.

Propriedades nos Arquivos ASCX

Hoje precisei criar propriedades de leitura (Public Property) dentro do meu arquivo ASCX para que eles sejam acessíveis fora dele, ou seja, precisava usar esses dados no meu WebForm (ASPX). No primeiro momento criei as propriedades:

Private m_nome As String
Private m_email As String

Public ReadOnly Property Nome As String
    Get
        Return Me.m_nome
    End Get
End Property

Public ReadOnly Property EmailAs String
    Get
        Return Me.m_email 
    End Get
End Property

Até aqui sem problemas. Arrastei o meu WebUserControl (ASCX) para dentro de meu WebForm(ASPX) e no evento Page_Load do meu WebForm estava fazendo:

Private MeuUserControl As WUCTopo

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Response.Write(MeuUserControl.Nome)
    Response.Write(MeuUserControl.Email)
End Sub

Só que nesse caso sempre os valores eram nulos. Quando decidi rodar em Debug com BreakPoints para ver o que acontecia, vi que o Evento Page_Load do WebForm (ASPX) é executado antes do mesmo Evento (Page_Load) do WebUserControl (ASCX). Com isso a solução foi usar o Evento Page_PreRender que é executado antes da página ser exibida, mas é chamado após todo o processamento dentro dos WebUserControls. Abaixo o código correto:

Private Sub Page_PreRender(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
    Response.Write(MeuUserControl.Nome)
    Response.Write(MeuUserControl.Email)
End Sub

Então a ordem de execução dos Eventos fica:

1 – Executa o Evento Page_Load do WebForm (ASPX).
2 – Executa o Evento Page_Load  WebUserControl (ASCX).
3 – Executa o Evento Page_PreRender do WebForm (ASPX).
4 – Executa o Evento Page_PreRender do WebUserControl (ASCX).

Agora fica claro porque no Evento Page_Load do WebForm não conseguia visualizar as Propriedades. 😉