Nova forma de utilizar cache utilizando Visual Studio.NET 2005
Bom, meu objetivo é mostrar como criar de uma nova forma cache de acesso a dados com pool de conexões. Com o uso da internet e as facilidades que a mesma atribui a todos que a utilizam, surgiu outra preocupação com softwares e sites dinâmicos, acesso a banco de dados, número de pessoas que acessam sistemas pela internet. A rapidez das informações mostradas ao cliente conta muito para que haja confiança e credibilidade pela parte do usuário.
Imagine uma pessoa acessando ao site que automaticamente busca a informação do banco de dados, não importa qual banco. Um cliente acessando o banco de dados é bem tranqüilo, agora imagine 10.000 clientes ao mesmo tempo acessando o mesmo site de notícias ou de venda de produtos. Se o software desenvolvido não foi preparado para essa quantidade de pessoas acessando ao mesmo momento, pode ocorrer um risco de travar ou elevar o nível de processamento e memória do servidor, ou seja, caso não tratado de uma forma correta, pool de conexões ou aproveitamento de conexão já criada, pode demorar por demais mostrar ao usuário ou cliente a notícia ou produto. Quem perde é você dono do site ou empreendimento de vendas, nos dias de hoje os usuários já não têm muita paciência para esperar muito tempo, isso é um erro muito grave junto aos jovens, crianças e adultos; não saber esperar 30 segundos, 10 segundos, o que seja.
Referências necessárias:
- Framework 2.0;
- Visual Studio .NET 2005;
- Sql Express 2005;
- Linguagem C#.NET;
- Imagine que um projeto do tipo WEB já esteja criado.
A criação de cache e pool de conexão para a versão 2005 da IDE Visual Studio .NET está mais robusta e eficaz do que a versão anterior. O arquivo web.config já está preparado para a funcionalidade. O primeiro de tudo é criar e configurar o caching. Referência 1.1.
Arquivo WEB.CONFIG
<connectionStrings> <add name="SiteDB" connectionString="Data Source=.\SQLEXPRESS; Integrated Security=True; User Instance=True; AttachDBFilename=|DataDirectory|\AspNetDB.mdf;" providerName="System.Data.SqlClient"/> </connectionStrings> <system.web> <caching> <sqlCacheDependency enabled="true" pollTime="10000"> <databases> <add name="siteDB" connectionStringName="SiteDB" pollTime="2000"/> </databases> </sqlCacheDependency> </caching> </system.web> |
Referência: 1.1
Explicação:
A primeira tag <connectionStrings> é a nova forma utilizada para conexão com banco de dados sql express 2005. O nome do banco de dados criado é ASPNETDB.mdf. O nome “SiteDB” é para referenciá-lo dentro do código C#.NET a string de conexão.
<caching> <sqlCacheDependency enabled="true" pollTime="10000"> <databases> <add name="siteDB" connectionStringName="SiteDB" pollTime="2000"/> </databases> </sqlCacheDependency> </caching> |
Referência: 1.2
A tag está localizada dentro da <system.web> logo após do fecho </connectionStrings>. Habilito o sqlCacheDependecy com o pollTime igual a 10000. Abri uma outra tag chamada <databases> onde defino qual a conexão do banco de dados utilizar com um pollTime específico a ele.
<add name="siteDB" connectionStringName="SiteDB" pollTime="2000"/> |
Referência: 1.3
Na referência 1.3, adicionei um nome “siteDB” minúsculo onde indico a connectionStringName referenciada na string de conexão anteriormente, ou seja, a que está dentro da <connectionStrings>. O atributo connectionStringName possui o mesmo nome da connectionString, isso significa que foi referenciado qual o pool escolhido para determinado banco de dados. Essa nova funcionalidade é legal porque posso referencia ou colocar quantos bancos de dados quiser para dentro da aplicação. Grave bem o atributo name adicionado de forma minúscula, usarei em breve dentro do código para fazer o caching.
Depois de configurado no web.config vou direto para o banco de dados definir tabela e campos. Referência 1.4.
Referência: 1.4
No banco de dados defini apenas dois campos como na figura de referência 1.4. Não esqueça de colocar o campo ID como auto-incremento. O campo CustomerName é do tipo nvarchar e do tamanho de 100 caracteres, ou seja, serve apenas para colocar o nome.
Este banco foi criado utilizando a IDE Visual Studio.NET 2005 pela aba SOLUTION EXPLORER. (Referência 1.5)
Referência: 1.5
Depois de criado o banco de dados, populei alguns dados.
Codificando código na classe
Cliquei com o botão direito do mouse em cima do projeto e adicionei um novo item cujo o “template” é o “Class”. Coloquei o nome de CustomerDetails.cs que ficou dentro da pasta APP_CODE. Dentro da classe adicionei apenas Get e Set dos campos criados no banco de dados, ou seja, mapeamento do banco de dados. Referência 1.6
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; /// <summary> /// Summary description for CustomerDetails /// </summary> public class CustomerDetails { public CustomerDetails() { // // TODO: Add constructor logic here // } private int _id; private string _customerName; public string CustomerName { get { return _customerName; } set { _customerName = value; } } public int Id { get { return _id; } set { _id = value; } } } |
Referência: 1.6
Note que declarei as variáveis, uma do tipo int e outra do tipo string. Para gerar o Get e Set automático, utilize o atalho CRTL + R e CRTL + E posicionado o mouse em cima da variável. Caso contrário utilize o menu refactory / encapsulate field...
Referência: 1.7
A referência 1.7 mostra o local correto onde ficou a classe criada apenas com o Get e Set dos campos. Depois de montado e configurado corretamente, criei a página “Default.aspx” para mostrar os resultados.
Aviso antes que não utilizarei o padrão MVC porque iria aumentar muito este artigo falando apenas de MVC, cujo não é o nosso objetivo, mas sim mostrar como funciona o novo sistema utilizando cache e sqldependency.
Dentro da página “Default.aspx”, adicionei o componente GridView com dois campos BoundField. Estes dois campos foram declarados com o mesmo nome da classe “CustomerDetails.cs”. Referência 1.8
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>CACHE</title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"> <Columns> <asp:BoundField DataField="id" /> <asp:BoundField DataField="customerName" /> </Columns> </asp:GridView> </div> </form> </body> </html> |
Referência: 1.8
Dentro da classe “Default.aspx.cs” é onde está o segredo para o cache. No Page_Load preencho o componente GridView chamando um método. Referência 1.9.
protected void Page_Load(object sender, EventArgs e) { this.GridView1.DataSource = GetDados(); this.GridView1.DataBind(); } |
Referência: 1.9
GetDados() é um método que retorna um List<CustomerDetails> utilizando genérics. Antes de criar o método, importe as seguintes classes. Referência 1.10.
//importes using System.Web.Caching; using System.Data.SqlClient; using System.Collections.Generic; |
Referência: 1.10
O método GetDados não recebe parâmetros porém retorna uma lista de dados. Utilizarei SqlDataReader para buscar os dados e preencher a lista.
private List<CustomerDetails> GetDados() { List<CustomerDetails> customers = null; if (Cache["Customers"] != null) { customers = (List<CustomerDetails>)Cache["Customers"]; } else { using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString)) { try { SqlCommand cmd = new SqlCommand("Select id, CustomerName from Customers", cn); cn.Open(); List<CustomerDetails> list = new List<CustomerDetails>(); customers = FillDados(cmd, list); System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString); SqlCacheDependencyAdmin.EnableTableForNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString, "Customers"); SqlCacheDependency dep = new SqlCacheDependency("siteDB", "Customers"); Cache.Insert("Customers", customers, dep); } catch (DatabaseNotEnabledForNotificationException ex) { throw ex; } } } return customers; } |
Referência: 1.11
Explicação:
Antes de tudo, a análise da assinatura do método é muito importante para o resto do entendimento. Referência 1.12.
private List<CustomerDetails> GetDados() |
Referência: 1.12
É do tipo privado, não recebe dados e retorna um List<CustomerDetails> cujo é a classe criada anteriormente.
List<CustomerDetails> customers = null; if (Cache["Customers"] != null) { customers = (List<CustomerDetails>)Cache["Customers"]; } |
Referência: 1.13
O próximo passo foi declarar uma lista chamada customers igualando ao valor null. Em seguida adicionei uma condição perguntando se o “Cache[“Customers”]” é diferente de null, caso for, a lista “customers” declarada acima receber um cache de dados do Cache[“Customers”].
Caso não tiver preenchido será necessário ir ao banco de dados utilizando a string de conexão do web.config, fazer um select, buscar os dados e preencher a lista de dados. Referência 1.14
else { using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString)) { try { SqlCommand cmd = new SqlCommand("Select id, CustomerName from Customers", cn); cn.Open(); List<CustomerDetails> list = new List<CustomerDetails>(); customers = FillDados(cmd, list); System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString); SqlCacheDependencyAdmin.EnableTableForNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString, "Customers"); SqlCacheDependency dep = new SqlCacheDependency("siteDB", "Customers"); Cache.Insert("Customers", customers, dep); } catch (DatabaseNotEnabledForNotificationException ex) { throw ex; } } } |
Referência: 1.14
No else, a primeira linha é buscar a conection string. Referência 1.15
using (SqlConnection cn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString)) |
Referência: 1.15
Lembre-se que dentro do web.config existe o nome [SiteDB] cujo é a conectionstring adicionada logo no começo deste artigo. Passando para as próximas linhas do código, adicionei try e catch onde faz select no banco de dados, executa datareader, preenche os dados e faz o cache. Referência 1.16
try { SqlCommand cmd = new SqlCommand("Select id, CustomerName from Customers", cn); cn.Open(); List<CustomerDetails> list = new List<CustomerDetails>(); customers = FillDados(cmd, list); System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString); SqlCacheDependencyAdmin.EnableTableForNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString, "Customers"); SqlCacheDependency dep = new SqlCacheDependency("siteDB", "Customers"); Cache.Insert("Customers", customers, dep); } catch (DatabaseNotEnabledForNotificationException ex) { throw ex; } |
Referência: 1.16
Explicação:
Logo após o try adicionei um SqlCommand com um select dos campos, abri o banco de dados com o comando Open() e criei uma nova variável list do tipo List<CustomerDetails>. Referência 1.17.
SqlCommand cmd = new SqlCommand("Select id, CustomerName from Customers", cn); cn.Open(); List<CustomerDetails> list = new List<CustomerDetails>(); |
Referência: 1.17
Dentro deste método, acabei acessando outro para buscar e executar o SqlDataReader adicionando na lista todo o resultado. Este método chama “FillDados”.
customers = FillDados(cmd, list); |
Referência: 1.18
Note que este novo método recebe como entrada SqlCommand e a lista de dados. A lista customers recebe o resultado do método. Antes de terminar o método “GetDados”, mostrarei o método FillDados. Referência 1.19.
private List<CustomerDetails> FillDados(SqlCommand cmd, List<CustomerDetails> list) { using (SqlDataReader dataReader = cmd.ExecuteReader()) { while (dataReader.Read()) { CustomerDetails coll = new CustomerDetails(); coll.Id = (int)dataReader["id"]; coll.CustomerName=(String)dataReader["CustomerName"]; list.Add(coll); } } } |
Referência: 1.19
Explicação:
Adicionei a variável dataReader executando o comando cmd.ExecuteReader(). Enquanto estiver dados crio uma variável “coll” do tipo CustomerDetails e atribuo os campos Id igual ao resultado do Reader[“id”]. Da mesma forma faço com o CustomerName; adiciono o dataReader[“CustomerName”] e ao final pego a lista criada e adiciono com o Add(coll) passando a variável coll.
Ao final preciso retornar uma lista, esta lista deve ser do tipo List<CustomerDetails> cujo tenho o list. Referência 1.20.
return list; |
Referência: 1.20
Após retornar a list do método “FillDados” preciso habilitar o cache pelo sqlCacheDependencyAdmin cujo deixo ativo o banco de dados para cache. Preciso habilitar a tabela do banco de dados utilizando o EnableTableForNotifications. No final insiro o cache utilizando o método Cache.Insert. Referência 1.21
customers = FillDados(cmd, list); //habilita o cache para o banco de dados para o uso do cache System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString); //habilita a tabela do banco de dados para o uso do cache SqlCacheDependencyAdmin.EnableTableForNotifications(System.Configuration.ConfigurationManager.ConnectionStrings["SiteDB"].ConnectionString, "Customers"); SqlCacheDependency dep = new SqlCacheDependency("siteDB","Customers"); //inserir o cache Cache.Insert("Customers", customers, dep); |
Referência: 1.21
Explicação:
Note que a linha que habilita o SqlCacheDependencyAdmin serve para autorizar que determinado banco de dados possa utilizar cache. Tenho que passar como parâmetro a conectionString dentro do web.config.
SqlCacheDependency dep = new SqlCacheDependency("siteDB","Customers"); |
Referência: 1.22
Na referência 1.22 é onde indico o nome da tag informada dentro do web.config e o nome da tabela cujo desejo fazer o cache. Logo após basta utilizar o cache.Insert passando a variável criada do tipo SqlCacheDependecy.
Cache.Insert("Customers", customers, dep); |
Referência: 1.23
Com este método, coloco a chave como parâmetro, a lista de dados e a variável cache. Vejamos o funcionamento do sistema.
Cliquei F5 para iniciar o sistema.
Referência: 1.24
Pela primeira vez, o cache ainda não foi feito, portanto o mesmo utiliza o select com todo o procedimento. Coloquei um breakpoint junto ao método PAGE_LOAD. Referência 1.25.
Referência: 1.25
Apertei F5 no browser e notei que não passou nem mesmo pelo breakpoint que coloquei, ou seja, foi criado um cache cujo nem mesmo precisou acessar o método para retornar os dados.
Bom, espero que tenham gostado. Fico por aqui e qualquer problema favor entrar em contato pelo e-mail: mauricio@aspneti.com ou mauricio@ascompras.com.
Mauricio Junior
Sign up to our newsletter
Receive our latest updates about programming languages, software, database, books, ebooks, classes, jobs and more.