Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Scott Mitchell
Em qualquer aplicativo Web, alguns dados serão usados com freqüência e alguns dados serão usados com pouca frequência. Podemos melhorar o desempenho da nossa aplicação ASP.NET carregando antecipadamente os dados frequentemente utilizados, uma técnica conhecida como. Este tutorial demonstra uma abordagem para o carregamento proativo, que é carregar dados no cache na inicialização do aplicativo.
Introdução
Os dois tutoriais anteriores analisaram o armazenamento em cache de dados nas camadas de apresentação e cache. Em Caching Data with the ObjectDataSource, analisamos o uso dos recursos de cache de ObjectDataSource para armazenar dados em cache na Camada de Apresentação. O Caching Data in the Architecture examinou o cache em uma nova camada de cache separada. Ambos os tutoriais usaram carregamento reativo ao trabalhar com o cache de dados. Com o carregamento reativo, cada vez que os dados são solicitados, o sistema primeiro verifica se eles estão no cache. Caso contrário, ele captura os dados da fonte de origem, como o banco de dados, e os armazena no cache. A principal vantagem do carregamento reativo é a sua facilidade de implementação. Uma das suas desvantagens é o seu desempenho desigual entre pedidos. Imagine uma página que usa a camada de cache do tutorial anterior para exibir informações do produto. Quando esta página é visitada pela primeira vez, ou visitada pela primeira vez depois que os dados armazenados em cache foram removidos devido a restrições de memória ou a expiração especificada ter sido atingida, os dados devem ser recuperados do banco de dados. Portanto, essas solicitações de usuários levarão mais tempo do que as solicitações de usuários que podem ser atendidas pelo cache.
O carregamento proativo fornece uma estratégia alternativa de gerenciamento de cache que suaviza o desempenho entre solicitações, carregando os dados armazenados em cache antes que sejam necessários. Normalmente, o carregamento proativo usa algum processo que verifica periodicamente ou é notificado quando há uma atualização nos dados subjacentes. Em seguida, esse processo atualiza o cache para mantê-lo atualizado. O carregamento proativo é especialmente útil se os dados subjacentes vierem de uma conexão de banco de dados lenta, um serviço Web ou alguma outra fonte de dados particularmente lenta. Mas essa abordagem de carregamento proativo é mais difícil de implementar, pois requer a criação, o gerenciamento e a implantação de um processo para verificar se há alterações e atualizar o cache.
Outro tipo de carregamento proativo, e o tipo que exploraremos neste tutorial, é o carregamento de dados no cache na inicialização do aplicativo. Essa abordagem é especialmente útil para armazenar em cache dados estáticos, como os registros em tabelas de pesquisa de banco de dados.
Observação
Para obter uma visão mais aprofundada das diferenças entre carregamento proativo e reativo, bem como listas de prós, contras e recomendações de implementação, consulte a seção Gerenciando o conteúdo de um cache do Guia de arquitetura de cache para aplicativos .NET Framework.
Etapa 1: Determinando quais dados armazenar em cache na inicialização do aplicativo
Os exemplos de cache usando carregamento reativo que examinamos nos dois tutoriais anteriores funcionam bem com dados que podem mudar periodicamente e não levam muito tempo para serem gerados. Mas se os dados armazenados em cache nunca forem alterados, a expiração usada pelo carregamento reativo será supérflua. Da mesma forma, se os dados que estão sendo armazenados em cache levarem um tempo excessivamente longo para serem gerados, os usuários cujas solicitações encontrarem o cache vazio terão que suportar uma longa espera enquanto os dados subjacentes são recuperados. Considere armazenar em cache dados estáticos e dados que levam um tempo excepcionalmente longo para gerar na inicialização do aplicativo.
Embora os bancos de dados tenham muitos valores dinâmicos e que mudam com frequência, a maioria também tem uma quantidade razoável de dados estáticos. Por exemplo, praticamente todos os modelos de dados têm uma ou mais colunas que contêm um valor específico de um conjunto fixo de opções. Uma Patients
tabela de banco de dados pode ter uma PrimaryLanguage
coluna, cujo conjunto de valores pode ser inglês, espanhol, francês, russo, japonês e assim por diante. Muitas vezes, esses tipos de colunas são implementados usando tabelas de pesquisa. Em vez de armazenar a cadeia de caracteres inglês ou francês na Patients
tabela, é criada uma segunda tabela que tem, geralmente, duas colunas - um identificador exclusivo e uma descrição de cadeia de caracteres - com um registro para cada valor possível. A PrimaryLanguage
coluna na tabela armazena Patients
o identificador exclusivo correspondente na tabela de pesquisa. Na Figura 1, a língua principal do paciente John Doe é o inglês, enquanto a de Ed Johnson é o russo.
Figura 1: A Languages
tabela é uma tabela de pesquisa usada pela Patients
tabela
A interface do usuário para editar ou criar um novo paciente incluiria uma lista suspensa de idiomas permitidos preenchida pelos registros na Languages
tabela. Sem cache, cada vez que esta interface é visitada o sistema deve consultar a Languages
tabela. Isso é um desperdício e desnecessário, uma vez que os valores da tabela de pesquisa mudam muito raramente, ou nunca.
Poderíamos armazenar os Languages
dados em cache usando as mesmas técnicas de carregamento reativo examinadas nos tutoriais anteriores. O carregamento reativo, no entanto, usa uma expiração baseada em tempo, que não é necessária para dados estáticos da tabela de pesquisa. Embora o cache usando carregamento reativo seja melhor do que nenhum cache, a melhor abordagem seria carregar proativamente os dados da tabela de pesquisa no cache na inicialização do aplicativo.
Neste tutorial, veremos como armazenar em cache dados da tabela de pesquisa e outras informações estáticas.
Etapa 2: Examinando as diferentes maneiras de armazenar dados em cache
As informações podem ser programaticamente armazenadas em cache em um aplicativo ASP.NET usando uma variedade de abordagens. Já vimos como usar o cache de dados em tutoriais anteriores. Como alternativa, os objetos podem ser programaticamente armazenados em cache usando membros estáticos ou o estado do aplicativo.
Ao trabalhar com uma classe, normalmente a classe deve primeiro ser instanciada antes que seus membros possam ser acessados. Por exemplo, para invocar um método de uma das classes em nossa camada de lógica de negócios, devemos primeiro criar uma instância da classe:
Dim productsAPI As New ProductsBLL()
productsAPI.SomeMethod()
productsAPI.SomeProperty = "Hello, World!"
Antes de podermos invocar SomeMethod ou trabalhar com SomeProperty, devemos primeiro criar uma instância da classe usando a New
palavra-chave.
SomeMethod e SomeProperty estão associados a uma instância específica. O tempo de vida desses membros está ligado ao tempo de vida de seu objeto associado.
Os membros estáticos, por outro lado, são variáveis, propriedades e métodos que são compartilhados entre todas as instâncias da classe e, consequentemente, têm uma vida útil tão longa quanto a classe. Membros estáticos são indicados pela palavra-chave Shared
.
Além dos membros estáticos, os dados podem ser armazenados em cache usando o estado do aplicativo. Cada aplicativo ASP.NET mantém uma coleção de nome/valor que é compartilhada entre todos os usuários e páginas do aplicativo. Essa coleção pode ser acessada usando a propriedade sHttpContext
da classe e usada a partir de uma classe code-behind da página de ASP.NET da seguinte forma:Application
Application("key") = value
Dim value As Object = Application("key")
O cache de dados fornece uma API muito mais rica para armazenar dados em cache, fornecendo mecanismos para expirações baseadas em tempo e dependência, prioridades de itens de cache e assim por diante. Com membros estáticos e estado do aplicativo, esses recursos devem ser adicionados manualmente pelo desenvolvedor da página. Ao armazenar dados em cache na inicialização do aplicativo durante o tempo de vida do aplicativo, no entanto, as vantagens do cache de dados são discutíveis. Neste tutorial, veremos o código que usa as três técnicas para armazenar dados estáticos em cache.
Etapa 3: Armazenando em cache os dados daSuppliers
tabela
As tabelas de banco de dados Northwind que implementamos até o momento não incluem nenhuma tabela de pesquisa tradicional. As quatro DataTables implementadas em nossa DAL todas as tabelas de modelo cujos valores são não-estáticos. Em vez de gastar o tempo para adicionar um novo DataTable para o DAL e, em seguida, uma nova classe e métodos para o BLL, para este tutorial vamos apenas fingir que os dados da Suppliers
tabela são estáticos. Portanto, poderíamos armazenar esses dados em cache na inicialização do aplicativo.
Para começar, crie uma nova classe nomeada StaticCache.cs
na CL
pasta.
Figura 2: Criar a StaticCache.vb
CL
classe na pasta
Precisamos adicionar um método que carregue os dados na inicialização no armazenamento de cache apropriado, bem como métodos que retornem dados desse cache.
<System.ComponentModel.DataObject()> _
Public Class StaticCache
Private Shared suppliers As Northwind.SuppliersDataTable = Nothing
Public Shared Sub LoadStaticCache()
' Get suppliers - cache using a static member variable
Dim suppliersBLL As New SuppliersBLL()
suppliers = suppliersBLL.GetSuppliers()
End Sub
<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
Return suppliers
End Function
End Class
O código acima usa uma variável de membro estático, suppliers
, para armazenar os resultados do SuppliersBLL
método s GetSuppliers()
da classe, que é chamado a partir do LoadStaticCache()
método. O LoadStaticCache()
método deve ser chamado durante o início do aplicativo. Depois que esses dados forem carregados na inicialização do aplicativo, qualquer página que precise trabalhar com dados do fornecedor poderá chamar o método s StaticCache
da GetSuppliers()
classe. Portanto, a chamada para o banco de dados para obter os fornecedores só acontece uma vez, no início da aplicação.
Em vez de usar uma variável de membro estático como armazenamento de cache, poderíamos ter usado alternativamente o estado do aplicativo ou o cache de dados. O código a seguir mostra a classe retooled para usar o estado do aplicativo:
<System.ComponentModel.DataObject()> _
Public Class StaticCache
Public Shared Sub LoadStaticCache()
' Get suppliers - cache using application state
Dim suppliersBLL As New SuppliersBLL()
HttpContext.Current.Application("key") = suppliers
End Sub
<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
Return TryCast(HttpContext.Current.Application("key"), _
Northwind.SuppliersDataTable)
End Function
End Class
No LoadStaticCache()
, as informações do fornecedor são armazenadas na chave variável do aplicativo. Ele é retornado como o tipo apropriado (Northwind.SuppliersDataTable
) de GetSuppliers()
. Enquanto o estado do aplicativo pode ser acessado nas classes code-behind de páginas ASP.NET usando Application("key")
, na arquitetura que devemos usar HttpContext.Current.Application("key")
para obter o atual HttpContext
.
Da mesma forma, o cache de dados pode ser usado como um armazenamento de cache, como mostra o código a seguir:
<System.ComponentModel.DataObject()> _
Public Class StaticCache
Public Shared Sub LoadStaticCache()
' Get suppliers - cache using a static member variable
Dim suppliersBLL As New SuppliersBLL()
HttpRuntime.Cache.Insert("key", suppliers, Nothing, _
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, _
CacheItemPriority.NotRemovable, Nothing)
End Sub
<System.ComponentModel.DataObjectMethodAttribute_
(System.ComponentModel.DataObjectMethodType.Select, True)> _
Public Shared Function GetSuppliers() As Northwind.SuppliersDataTable
Return TryCast(HttpRuntime.Cache("key"), Northwind.SuppliersDataTable)
End Function
End Class
Para adicionar um item ao cache de dados sem expiração baseada em tempo, use os System.Web.Caching.Cache.NoAbsoluteExpiration
valores e System.Web.Caching.Cache.NoSlidingExpiration
como parâmetros de entrada. Essa sobrecarga específica do método de cache de Insert
dados foi selecionada para que pudéssemos especificar a prioridade do item de cache. A prioridade é usada para determinar quais itens devem ser removidos do cache quando a memória disponível estiver baixa. Aqui usamos a prioridade NotRemovable
, que garante que esse item de cache não será removido.
Observação
O download deste tutorial implementa a StaticCache
classe usando a abordagem de variável de membro estático. O código para o estado do aplicativo e técnicas de cache de dados está disponível nos comentários no arquivo de classe.
Etapa 4: Executando código na inicialização do aplicativo
Para executar código quando um aplicativo Web é iniciado pela primeira vez, precisamos criar um arquivo especial chamado Global.asax
. Esse arquivo pode conter manipuladores de eventos para eventos de nível de aplicativo, sessão e solicitação, e é aqui que podemos adicionar código que será executado sempre que o aplicativo for iniciado.
Adicione o arquivo ao diretório raiz do aplicativo Web clicando com o Global.asax
botão direito do mouse no nome do projeto do site no Gerenciador de Soluções do Visual Studio e escolhendo Adicionar Novo Item. Na caixa de diálogo Adicionar Novo Item, selecione o tipo de item Classe de Aplicativo Global e clique no botão Adicionar.
Observação
Se você já tiver um Global.asax
arquivo em seu projeto, o tipo de item Classe de Aplicativo Global não será listado na caixa de diálogo Adicionar Novo Item.
Figura 3: Adicionar o arquivo ao diretório raiz do aplicativo Web (Global.asax
imagem em tamanho real)
O modelo de arquivo padrão Global.asax
inclui cinco métodos dentro de uma marca do lado <script>
do servidor:
-
Application_Start
Executa quando o aplicativo Web é iniciado pela primeira vez -
Application_End
é executado quando o aplicativo está sendo desligado -
Application_Error
é executado sempre que uma exceção não tratada chega ao aplicativo -
Session_Start
Executa quando uma nova sessão é criada -
Session_End
é executado quando uma sessão expira ou é abandonada
O Application_Start
manipulador de eventos é chamado apenas uma vez durante o ciclo de vida de um aplicativo. O aplicativo é iniciado na primeira vez que um recurso de ASP.NET é solicitado do aplicativo e continua a ser executado até que o aplicativo seja reiniciado, o que pode acontecer modificando o /Bin
conteúdo da pasta, modificando Global.asax
, modificando o App_Code
conteúdo na pasta ou modificando o Web.config
arquivo, entre outras causas. Consulte ASP.NET Visão geral do ciclo de vida do aplicativo para obter uma discussão mais detalhada sobre o ciclo de vida do aplicativo.
Para esses tutoriais, só precisamos adicionar código ao Application_Start
método, então sinta-se à vontade para remover os outros. No Application_Start
, basta chamar o StaticCache
método de classe s LoadStaticCache()
, que carregará e armazenará em cache as informações do fornecedor:
<%@ Application Language="VB" %>
<script runat="server">
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
StaticCache.LoadStaticCache()
End Sub
</script>
É só isso! Na inicialização do aplicativo, o LoadStaticCache()
método pegará as informações do fornecedor da BLL e as armazenará em uma variável de membro estática (ou qualquer armazenamento de cache que você acabou usando na StaticCache
classe). Para verificar esse comportamento, defina um ponto de interrupção no método e execute seu Application_Start
aplicativo. Observe que o ponto de interrupção é atingido ao iniciar o aplicativo. Solicitações subsequentes, no entanto, não fazem com que o Application_Start
método seja executado.
Figura 4: Usar um ponto de interrupção para verificar se o manipulador de eventos está sendo executado (Application_Start
imagem em tamanho real)
Observação
Se você não atingir o ponto de interrupção quando iniciar a Application_Start
depuração pela primeira vez, é porque seu aplicativo já foi iniciado. Força a reinicialização do aplicativo modificando seus Global.asax
arquivos ou Web.config
e tente novamente. Você pode simplesmente adicionar (ou remover) uma linha em branco no final de um desses arquivos para reiniciar rapidamente o aplicativo.
Etapa 5: Exibindo os dados armazenados em cache
Neste ponto, a StaticCache
classe tem uma versão dos dados do fornecedor armazenados em cache na inicialização do aplicativo que pode ser acessada por meio de seu GetSuppliers()
método. Para trabalhar com esses dados da camada de apresentação, podemos usar um ObjectDataSource ou invocar programaticamente o StaticCache
método s da classe a GetSuppliers()
partir de uma classe code-behind da página ASP.NET. Vamos examinar o uso dos controles ObjectDataSource e GridView para exibir as informações do fornecedor armazenadas em cache.
Comece por abrir a página AtApplicationStartup.aspx
na pasta Caching
. Arraste um GridView da Caixa de Ferramentas para o designer, definindo sua ID
propriedade como Suppliers
. Em seguida, na marca inteligente de GridView, escolha criar um novo ObjectDataSource chamado SuppliersCachedDataSource
. Configure o ObjectDataSource para usar o método s da StaticCache
GetSuppliers()
classe.
Figura 5: Configurar o ObjectDataSource para usar a classe (StaticCache
imagem em tamanho real)
Figura 6: Use o método para recuperar os dados do fornecedor armazenados em cache (GetSuppliers()
imagem em tamanho real)
Depois de concluir o assistente, o Visual Studio adicionará automaticamente BoundFields para cada um dos campos de dados no SuppliersDataTable
. Sua marcação declarativa de GridView e ObjectDataSource deve ser semelhante à seguinte:
<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
InsertVisible="False" ReadOnly="True"
SortExpression="SupplierID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
SortExpression="CompanyName" />
<asp:BoundField DataField="Address" HeaderText="Address"
SortExpression="Address" />
<asp:BoundField DataField="City" HeaderText="City"
SortExpression="City" />
<asp:BoundField DataField="Country" HeaderText="Country"
SortExpression="Country" />
<asp:BoundField DataField="Phone" HeaderText="Phone"
SortExpression="Phone" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetSuppliers" TypeName="StaticCache" />
A Figura 7 mostra a página quando visualizada através de um navegador. A saída é a mesma se tivéssemos extraído os dados da classe BLL s SuppliersBLL
, mas usar a StaticCache
classe retorna os dados do fornecedor como armazenados em cache na inicialização do aplicativo. Você pode definir pontos de interrupção no método s StaticCache
de GetSuppliers()
classe para verificar esse comportamento.
Figura 7: Os dados do fornecedor em cache são exibidos em um GridView (Clique para visualizar a imagem em tamanho real)
Resumo
A maioria dos modelos de dados contém uma quantidade razoável de dados estáticos, geralmente implementados na forma de tabelas de pesquisa. Uma vez que esta informação é estática, não há razão para aceder continuamente à base de dados cada vez que esta informação precisa de ser apresentada. Além disso, devido à sua natureza estática, ao armazenar os dados em cache, não há necessidade de um prazo de validade. Neste tutorial, vimos como pegar esses dados e armazená-los em cache no cache de dados, no estado do aplicativo e por meio de uma variável membro estática. Essas informações são armazenadas em cache na inicialização do aplicativo e permanecem no cache durante todo o tempo de vida do aplicativo.
Neste tutorial e nos dois anteriores, analisamos os dados de cache durante o tempo de vida do aplicativo, bem como o uso de expirações baseadas no tempo. Ao armazenar dados de banco de dados em cache, no entanto, uma expiração baseada em tempo pode ser menos do que ideal. Em vez de liberar periodicamente o cache, seria ideal remover apenas o item armazenado em cache quando os dados do banco de dados subjacente forem modificados. Esse ideal é possível através do uso de dependências de cache SQL, que examinaremos em nosso próximo tutorial.
Feliz Programação!
Sobre o Autor
Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.
Um agradecimento especial a
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Teresa Murphy e Zack Jones. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.