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.
<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:
|
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:
|
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.
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.
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