ASP.NET - Application, Session, ViewState e HttpContext Caching


Você pode usar os objetos Application, Session, ViewState e HttpContext para efetuar o cache de dados; esses objetos fornecem uma coleção baseada em chaves para armazenamento de dados durante o tempo de vida do objeto. Como não há persistência para esses objetos você deve armazenar somente dados temporários, se você precisar armazenar os dados por um período maior de tempo deverá usar um banco de dados ou talvez um objeto Profile.

Usando o objeto Application

O objeto Application existe durante o tempo de vida da aplicação, ou seja, a partir do momento que a primeira requisição for recebida até o momento que a aplicação é parada. Lembre-se que a sua aplicação pode ser reiniciada de forma automática por um problema de memória excedida, por exemplo. Então não pense que o objeto Application pode guardar dados sem riscos durante o tempo que a sua aplicação estiver em atendimento, dessa forma você deve sempre verificar para valores nulos.

Usar o objeto Application é muito simples. Exemplo:

Application["Start"] = DateTime.Now;   Application("Start") = DateTime.Now;
VB .NET C#

Este código irá incluir a data e hora atual no objeto Aplication, indice start. Para obter o valor , você deve usar o mesmo índice e efetuar a coersão(Cast) do valor de Object para DateTime para uma variável de ambiente:

Dim appStart DateTime = (DateTime) Application["Start"];   DateTime appStart = (DateTime)Application["Start"];
VB .NET C#

Existe uma preocupação quando você vai alterar o valor de uma variável Application em um determinado instante, várias sessões poderão estar tentando alterar o mesmo valor, embora apenas uma sessão possa ser autorizados a alterá-lo. O ASP .NEt possui um mecanismo interno de exclusão mútua para tratar com estes tipos de problemas:

Application.Lock – Bloqueia a aplicação variáveis 
Application.Unlock – - Desbloqueia a aplicação variáveis 

Imagine que dois usuários estejam visitando a página ao mesmo tempo e que o servidor web processe a requisição do primeiro usuário uma fração de segundos antes do segundo usuário efetuar a sua requisição.

O formulário web que foi carregado pelo primeiro usuário pode ler o contador de páginas do estado da aplicação e obter o valor 4, o qual será incrementado o valor de uma unidade obtendo assim 5.

Porém, antes do formulário armazenar este novo valor no estado da aplicação , outra copia do formulário, rodando na maquina do segundo usuário, poderá ler o contador de páginas e também obter o valor 4.

Desta forma ambos os formulários terão o mesmo valor e irão armazenar o valor incrementado igual a 5 no estado da aplicação. Assim o valor armazenado no estado da aplicação será igual a 5 e não igual a 6 como deveria.

Para evitar este problema  devemos bloquear o estado da aplicação quando o mesmo estiver sendo atualizado e liberar em seguida para outro usuário tenha acesso ao objeto Application.

O código usando este recurso é mostrado a seguir:

' Inicializa ou incrementa o contador de páginas
If Application("PageCounter") Is Nothing Then
    Application("PageCounter") = 1
Else
   'Bloqueia o objeto Application
   Application.Lock()
   ' Incrementa o contador
   Application("PageCounter") += 1
   ' Desbloqueia o objeto Application
   Application.UnLock()
End If

O método Lock garante que somente um usuário poderá acessar a variável da aplicação, e, em seguida o método Unlock libera a variável da aplicação para a próxima requisição. Desta forma estamos garantindo que o incremento seja realmente contado a cada visita de um usuário a página,

Usando o objeto Session

O objeto Session é muito similar ao objeto Application com um diferencial:ele é único para cada usuário do site e é destruído quando o usuário deixa o site (depois de um intervalo de tempo).

Nota: Sessões em ASP.NET são simplesmente tabelas hash na memória com um tempo limite especificado.

Dessa forma o objeto Session é útil para armazenar dados que o usuário irá requerer através do uso da aplicação; depois que o usuário deixar o site os dados serão perdidos após um intervalo de tempo. (Para armazenar as preferências do usuário você deve usar o objeto Profile ou cookies.)

Exemplo :

Session("nome")="Macoratti"
Session("idade")= 35
 Session["nome"]="Macoratti"
 Session["idade"]=35
VB .NET C#

Este código atribui os valores "Macoratti" e "35" para as variáveis de sessão nome e idade. Quando o valor esta armazenado em uma variável de sessão ele pode ser alcançado a partir de qualquer página na aplicação.

Dim nome as String = Session("nome")   ou  If   Session("idade") > 18 then  String nome = Session("nome")  ou   If( Session["idade"] > 18)

Vamos ver agora como você pode configurar o objeto sessão em função das necessidades do seu aplicativo da Web.

 Métodos Descrição Exemplo
Session.Abandon Abandona (anula) a sessão atual.  
Session.Remove Excluir um item da sessão de estado coleção. Session(“nome”) = “Macorattii”
Inicializar uma variável de sessão
Session.Remove(“nome”)
Session.RemoveAll Elimina todos os itens sessão estado  
Session.Timeout Define o tempo (em minutos) para uma sessão Session.Timeout = 30;

Se um usuário não solicitar uma página do ASP.NET pedido dentro de 30 minutos a sessão termina.)

Session.SessionID Obtém o sessão ID para a sessão atual.  
Session.IsNewSession Verifica se a sessão do visitante foi criado com a requisição atual ou seja se o visitante acabou de entrar no site.
A propriedade IsNewSession é True para a primeira página da aplicação ASP.NET.
 

Você também pode desabilitar o estado da sessão , uma forma de ganhar desempenho, usando o atributo EnableSessionState na diretiva Page:

<% Page EnableSessionState="false" ... %>

De outra forma, se você precisa acessar o estado da sessão mas não planeja atualizá-lo você pode torná-lo somente leitura para a página:

<% Page EnableSessionState="ReadOnly" ... %>

Com isto você tem certeza que você ainda tem acesso mas não vai sobrecarregar o estado da página com bloqueios para atualização.

Você pode configurar o estado da sessão no arquivo web.config. Exemplo:
<sessionState
  allowCustomSqlDatabase="[true|false]"
  cookieless="[AutoDetect|UseCookies|UseDeviceProfile|UseUri|true|false]"
  cookieName="String"
  customProvider="String"
  mode="[Custom|InProc|Off|StateServer|SQLServer|]"
  partitionResolverType="String"
  regenerateExpiredSessionId="[true|false]"
  sessionIdManagerType="String"
  sqlCommandTimeout="Integer"
  sqlConnectionString="String"
  stateConnectionString="String"
  stateNetworkTimeout="Integer"
  timeout="Integer"
  useHostingIdentity="[true|false]"
  >
  <providers>
    <clear />
    <add
      Name="String"
      Type="String"
      [providerSpecificConfiguration] />
  </providers>
</sessionState>

Veja a seguir um resumo sobre cada um dos atributos mais usados para configurar a sessão:

Atributo Descrição
allowCustomSqlDatabase Relevante somente quando o modo é definido para SQLServer, e indica nome do banco de dados pode ser usado ou não no atributo Initial Catalog da string de conexão. O valor padrão é false indicando que o o banco de dados padrão da sessão será usado;
cookieless Indica como os cookies são usados: Valores possíveis:
  • AutoDetect -O ASP.NET determina se o dispositivo que fez a requisição suporta cookies, neste caso os cookies serão usados.
  • UseCookies - Valor padrão - sempre usa os cookies;
  • UseDeviceProfile - O ASP.NET usa a capacidade dos navegador para determinar se os cookies serão usados.
  • UseUri - A string de consulta (QueryString) sempre será usada;
  • true - Tem o mesmo efeito que usar UseUri.
  • false - tem o mesmo feito que usar UseCookies.
cookieName Define o nome do cooke padrão usado para armazenar o ID da sessão.O padrão é: ASP.NET_SessionId.
customProvider Indica o nome do provedor quando o modo é Custom. O atributo name deverá ser igual a um dos nomes dos provedores declarados na seção <Providers/>
mode Indica como o estado da sessão esta sendo gerenciado e pode ser um dos seguintes valores:
  • Custom - indica que o estado da sessão é armazenado em uma maneira personalizada;
  • InProc -  Onde o estado da sessão armazenado no interior do processo ASP.NET.(Valor padrão);
  • Off - o estado da sessão é e desligado para a aplicação;
  • SQLServer - o estado da sessão é armazenado no SQL Server;
  • StateServer - o estado da sessão é armazenado em um serviço separado;
regenerateExpiredSessionId Indica se o identificador da sessão será reusado ou não quando um valor inválido for usando para o cliente. O valor padrão é True;
sqlCommandTimeout Indica , em segundos, o tempo de expiração para um comando SQL quando o modo usado for SQLServer. O valor padrão é 30.
sqlConnectionString Indica o nome da string de conexão quando usar SQL Server para armazenar o estado da sessão. O valor padrão é "data source=127.0.0.1; Integrated Security=SSPI", apontando para um banco de dados SQL Server local;
stateConnectionString Obrigatório quando o modo usado for StateServer, e define o nome/endereço do servidor e porta onde os dados da sessão é armazenada; O valor padrão é: "127.0.0.1:42424".
timeout Define o numero de minutos de espera depois da atividade da sessão antes que a sessão seja abandonada. O valor padrão é 20 minutos;

Note que  existem diversas formas nas quais o estado da sessão pode ser armazenado; Por padrão o processo ASP .NET armazena o estado (state) pois é a forma mais rápida.

Usando o HttpContext

Se você não precisa armazenar dados através de uma sessão mas precisa requisitar dados através de múltiplos controles de usuários em uma página, então você pode usar o contexto atual da requisição.

Cada requisição (request) possui um objeto HttpContect associado, o qual fornece acesso a muitos objetos usados nas páginas, tais como Request, Profile e Trace.

Dentre estes objetos temos disponível no contexto uma coleção de items que pode ser usada para armazenamento e que é particularmente útil quando você possui muitos controles de usuário em uma página que precisam compartilhar dados.

Note que esta técnica somente é válida entre controles dentro de uma única requisição e que ela não se aplica entre requisição de páginas separadas. Vejamos um exemplo.

Você possui uma página contendo alguns controles grids(GridView) que estão exibindo os dados dos clientes via método GetClientes() de sua classe Clientes da camada de acesso a dados. O código para exibir os dados no grid poderia ser o seguinte:

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GridView1.DataSource = Clientes.GetClientes();
GridView1.DataBind();
}
}

Este código se usado em múltiplos controles iria resultar em um mesmo comando SQL sendo executado repetidamente. Existem diversas formas de evitar isso, mas uma solução bem simples seria ler os dados para um controle e armazená-lo em cache no contexto.

Você poderia colocar o código desta solução em um controle e neste caso teria que se certificar de que o mesmo esta sendo executado primeiro para que os dados estejam no cache do controle.

Uma solução mais elegante seria criar uma classe usando o seguinte código usando o HttpContext:

public static class Caching
{
 public static List<Cliente> GetClientes()
 {
   List<Cliente> clientes = (List<Cliente>)HttpContext.Current.Items["Clientes"];
   if (clientes == null)
    {
        clientes = Clientes.GetItems();
        HttpContext.Current.Items["Clientes"] = clientes;
    }
   return clientes;
 }
}
Public Class Caching
    
    
Public Shared Function GetClientes() As List
        
Dim clientes As List = CType(HttpContext.Current.Items("Clientes"),List)
        
If (clientes Is Nothing) Then
            
clientes Clientes.GetItems
            HttpContext.Current.Items(
"Clientes"clientes
        
End If
        Return 
clientes
    
End Function
End Class
C# VB .NET

Este código é muito simples e segue o mesmo padrão usado no caching. Ele primeiro verifica os dados a partir da coleção items , e, se os mesmos não forem encontrados no cache, os dados são obtidos a partir da classe de negócio Clientes e armazenados na coleção Items. As próximas chamadas irão encontrar os dados na coleção.

Usando ViewState

Outro método usado para efetuar o cache dos dados é usar o ViewState. Embora você deve atentar para a sobrecarga de dados transmitida entre as páginas.

A string VIEWSTATE é armazenada em um campo oculto no HTML gerado para a página , ela é um conjunto de informações sobre a página mesclado com um HASH gerado no servidor para proteger a informação (Você pode decodificar esta string usando o ViewState Decoder). Então cada componente da página salva o seu estado no ViEWSTATE de forma que para cada postback o componente possa voltar a ser exibido na forma original sem necessitar de uma nova inicialização.(Você pode usar o ViewState para armazenar dados de sua aplicação desde que eles sejam aplicáveis somente a página.)

O ViewState pode ser acessado como qualquer outra coleção:

ViewState["dataEmCache"] = DateTime.Now;

Você deve procurar usar o ViewState o menos possível afim de reduzir a sobrecarga na transmissão das páginas, mas ele não deixa de ser uma alternativa de armazenar dados para pequenas quantidades de dados.

Para um melhor desempenho, você deverá desabilitar o ViewState para os controles das páginas que não vão precisar usá-lo.

A partir da ASP .NET 2.0 existe o suporte a uma nova característica para armazenar o estado, o Control-State, que os controles usam para suportar a exigência mínima de estado para o controle operar. Dessa forma podemos desabilitar o ViewState e ainda sim o controle continua a operar corretamente.

A ASP.NET 2.0 removeu a informação necessária para controlar o postback do ViewState; a informação sobre o postback agora esta contida no ControlState. Esta separação fornece maior flexibilidade para desabilitar o ViewState e assim reduzir o tamanho das páginas.

Com isso encerramos esta pequena recordação sobre a utilização dos objetos Application, Session , ViewState e HttpContext.

Eu sei é apensa ASP .NET , mas eu gosto...

Referências:


José Carlos Macoratti