Partilhar via


Armazenamento em cache de dados na inicialização do aplicativo (VB)

por Scott Mitchell

Descarregar PDF

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.

A Tabela de Idiomas é uma Tabela de Pesquisa usada pela Tabela de Pacientes

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 daSupplierstabela

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.

Criar a classe StaticCache.vb na pasta CL

Figura 2: Criar a StaticCache.vbCL 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.

Adicione o arquivo Global.asax ao diretório raiz do seu aplicativo Web

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.

Usar um ponto de interrupção para verificar se o manipulador de eventos Application_Start está sendo 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 StaticCacheGetSuppliers() classe.

Configurar o ObjectDataSource para usar a classe StaticCache

Figura 5: Configurar o ObjectDataSource para usar a classe (StaticCache imagem em tamanho real)

Use o método GetSuppliers() para recuperar os dados do fornecedor armazenados em cache

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.

Os dados do fornecedor em cache são exibidos em um GridView

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.