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