// Rodolfo Fadino

/* LIFE RUNS ON CODE */

O OutputCache é sem dúvida um do recursos mais essenciais do ASP.NET, ele está disponível desde a primeira versão do ASP.NET. Usar o OutputCache ajuda a melhorar em muito a performance de nossos projetos, evitando vários processamentos desnecessários, armazenando em memória o resultado final de uma página ou um controller, evitando assim que as mesmas informações sejam reprocessadas.

Abaixo segue um diagrama básico do seu funcionamento:

O ASP.NET 4.0 traz um modelo de provider para o módulo de OutputCache, facilitando as possibilidades para criar soluções de armazenamento de paginas em cache. Assim podemos facilmente estender o OutputCache de nossas aplicações, sendo necessário implementar o nosso provider com base na classe System.Web.Caching.OutputCacheProvider.

Existem diversos cenários e ambientes para a implementação do OutputCache, em cenários de Farm que não usam uma solução de cache centralizada, uma página que utiliza OutputCache fica na memória de cada um dos servidores do Farm, em uma solução centralizada, os vários servidores do farm consumiriam a mesma pagina que está cacheada em memória.

A idéia deste post é demonstrar como criar um Provider Custom para o OutputCache que armazene as informações em um servidor de Cache, neste exemplo eu utilizarei o Memcached.

Memcached

Memcached (http://memcached.org/) é um sistema distribuído de alto desempenho para o armazenamento de objetos em memória, é open source. Funciona armazenando e retornando objetos genéricos com base em um chaves. Seu design simples promove a implantação rápida, facilidade de desenvolvimento, resolve muitos problemas de performance em cache da grandes volumes. Com diversas API’s para várias linguagens.

Claro que, ao utilizar o Memcached em cenários de produção, é indispensável pensar em no mínimo duas instâncias, para garantir a continuidade de nossas aplicações em caso de falha em um dos servidores de Memcached.

Ao inicializar o Memcached para testes, no prompt, podemos utilizar os seguintes parâmetros:

C:\memcache>memcached.exe -vv -m512

-vv =verbose mode

-m521 = o memcached pode utilizar até 512 mbs de ram

Só é preciso descompactar o Memcached em um diretório e executa-lo.

Download Memcache

Para .NET eu utilizarei a seguinte biblioteca Memcached

Começando

Inicialmente eu criei dois projetos, um chamado DemoCache.Web que é em ASP.NET MVC3 e outro Class Library chamado DemoCache.Cache o qual eu já referenciei no projeto Web.

No Class Library eu adicionei e referenciei as DLL’s que eu utilizarei para acessar o Memcached, também adicionei referencia do System.Web ao projeto:

Com isso já podemos começar a desenvolver nosso provider para o OutputCache.

Vou criar uma classe chamada OutputCacheMemcachedProvider que herde de OutputCacheProvider (System.Web.Caching)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Caching;

namespace DemoCache.Cache
{
    public class OutputCacheMemcachedProvider : OutputCacheProvider
    {
        public override object Add(string key, object entry, DateTime utcExpiry)
        {
            throw new NotImplementedException();
        }

        public override object Get(string key)
        {
            throw new NotImplementedException();
        }

        public override void Remove(string key)
        {
            throw new NotImplementedException();
        }

        public override void Set(string key, object entry, DateTime utcExpiry)
        {
            throw new NotImplementedException();
        }
    }
}

Vamos criar 2 métodos, o primeiro servirá para transformar a chave(key) passada pelo ASP.NET em um Hash, formatando ela de uma maneira ideal para utilizar.

private string MD5(string value)
{
    var cryptoServiceProvider = new MD5CryptoServiceProvider();
    var bytes = Encoding.UTF8.GetBytes(value);
    var builder = new StringBuilder();

    bytes = cryptoServiceProvider.ComputeHash(bytes);

    foreach (var b in bytes)
        builder.Append(b.ToString("x2").ToLower());

    return builder.ToString();
}

O segundo método servirá para inicializar a conexão com o Memcached, ele pega uma key no arquivo de configuração, na qual pode ter vários endereços separados por virgula:

private MemcachedClient InitMemcached()
{
    var servers = ConfigurationManager.AppSettings["memCachedServers"].Split(',');
    var pool = SockIOPool.GetInstance();
    pool.SetServers(servers);
    pool.Initialize();

    return new MemcachedClient();
}

Chave no web.config

<add key="memCachedServers" value="127.0.0.1:11211"/>

Agora vamos implementar os métodos para manipular o OutputCache, são eles: Add, Get, Remove e Set.

O primeiro serve para adicionar os valores ao cache:

public override object Add(string key, object entry, DateTime utcExpiry)
{
    var memcachedClient = InitMemcached();
    var chave = MD5(key);

    utcExpiry = TimeZoneInfo.ConvertTimeFromUtc(utcExpiry, TimeZoneInfo.Local);

    if (memcachedClient.KeyExists(chave))
    {
        return memcachedClient.Get(chave);
    }
    else
    {
        memcachedClient.Set(chave, entry, utcExpiry);
        return entry;
    }
}

O outro é o Get, ele retornará o valor que está em cache ou retornará null

public override object Get(string key)
{
    var memcachedClient = InitMemcached();
    var chave = MD5(key);

    if (memcachedClient.KeyExists(chave))
        return memcachedClient.Get(chave);
    else
        return null;
}

O método Remove não será muito utilizado, já que o próprio Memcached expirará os conteúdos

public override void Remove(string key)
{
    var memcachedClient = InitMemcached();
    var chave = MD5(key);

    memcachedClient.Delete(chave);
    return;
}

O último método necessário será o Set, ele atualizará a expiração ou inserirá o valor no cache.

public override void Set(string key, object entry, DateTime utcExpiry)
{
    var memcachedClient = InitMemcached();
    var chave = MD5(key);

    utcExpiry = TimeZoneInfo.ConvertTimeFromUtc(utcExpiry, TimeZoneInfo.Local);

    memcachedClient.Set(chave, entry, utcExpiry);
    return;
}

Por fim, a classe do nosso Provider ficou da seguinte maneira:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web.Caching;
using Memcached.ClientLibrary;
using System.Configuration;

namespace DemoCache.Cache
{
    public class OutputCacheMemcachedProvider : OutputCacheProvider
    {
        public override object Add(string key, object entry, DateTime utcExpiry)
        {
            var memcachedClient = InitMemcached();
            var chave = MD5(key);

            utcExpiry = TimeZoneInfo.ConvertTimeFromUtc(utcExpiry, TimeZoneInfo.Local);

            if (memcachedClient.KeyExists(chave))
            {
                return memcachedClient.Get(chave);
            }
            else
            {
                memcachedClient.Set(chave, entry, utcExpiry);
                return entry;
            }
        }

        private MemcachedClient InitMemcached()
        {
            var servers = ConfigurationManager.AppSettings["memCachedServers"].Split(',');
            var pool = SockIOPool.GetInstance();
            pool.SetServers(servers);
            pool.Initialize();

            return new MemcachedClient();
        }

        private string MD5(string value)
        {
            var cryptoServiceProvider = new MD5CryptoServiceProvider();
            var bytes = Encoding.UTF8.GetBytes(value);
            var builder = new StringBuilder();

            bytes = cryptoServiceProvider.ComputeHash(bytes);

            foreach (var b in bytes)
                builder.Append(b.ToString("x2").ToLower());

            return builder.ToString();
        }

        public override object Get(string key)
        {
            var memcachedClient = InitMemcached();
            var chave = MD5(key);

            if (memcachedClient.KeyExists(chave))
                return memcachedClient.Get(chave);
            else
                return null;
        }

        public override void Remove(string key)
        {
            var memcachedClient = InitMemcached();
            var chave = MD5(key);

            memcachedClient.Delete(chave);
            return;
        }

        public override void Set(string key, object entry, DateTime utcExpiry)
        {
            var memcachedClient = InitMemcached();
            var chave = MD5(key);

            utcExpiry = TimeZoneInfo.ConvertTimeFromUtc(utcExpiry, TimeZoneInfo.Local);

            memcachedClient.Set(chave, entry, utcExpiry);
            return;
        }
    }
}

Para utilizarmos nos nosso projetos basta inserir no web.config, dentro do system.web a referencia para o nosso Provider

<caching>
  <outputCache defaultProvider="OutputCacheProvider">
    <providers>
      <add name="OutputCacheProvider" type="DemoCache.Cache.OutputCacheMemcachedProvider" />
    </providers>
  </outputCache>
</caching>

Isso fará com que o OutputCache de nossa aplicação já utilize o provider que criamos.

Projeto para download

Espero que este post seja útil,

estou a disposição para dúvidas, criticas e sugestões

 

Rodolfo

 

 

 

 

 

 

ASP.NET

Em diversas situações temos que adequar os elementos da pagina que estamos desenvolvendo ao layout que foi especificado, so que em alguns controles asp.net não fica claro como deve ser feita a aplicação do estilo para obter o efeito necessário. Ou então não sabemos ao certo que controle utilizar em cada situação

Para isso é essencial sabermos o qua cada controle renderiza na tela.

Vamos começar por dois controles muito utilizados, aparentemente com mesma função mais cada um com uma funcionalidade e comportamento diferente.

Label e Literal:

Label:

<asp:Label ID=”Label1″ runat=”server” Text=”Label”></asp:Label>

Renderização Pagina:

<span id=”Label1″>Label</span>

Literal

<asp:Literal ID=”Literal1″ runat=”server” Text=”Literal1″></asp:Literal>

Renderização Pagina:

Literal1
Aplicando estilos:

Em um Label podemos adicionar a cssClass diretamente no controle:

<asp:Label ID=”Label1″ runat=”server” CssClass=”style01“  Text=”Label”></asp:Label>

Será renderizado

<span id=”Label1″ class=”style01″>Label</span>

Já em um literal para obter o mesmo efeito será necessário colocar o controle Literal dentro de uma tag span com o estilo associado

<span class=”style02″>
<asp:Literal ID=”Literal1″ runat=”server” Text=”Literal1″></asp:Literal>
</span>

Será renderizado

<span class=”style02“> Literal1 </span>

Com isso o literal é mais indicado para quando se vai “escrever” html na pagina, como ao trazer um texto com formatação html de um Banco de Dados. Intuitivamente um label deve ser utilizado quando o texto precisar de uma formatação ou for necessário o texto estar dentro de uma tag span.

Obrigado

Rodolfo

*fonte(Taurã Figueiredo, a quem sempre me faz “pensar sobre o que eu estou programando”)

ASP.NET

Quando o assunto era gráfico, freqüentemente precisávamos adotar algum componente de terceiros, o que acabava gerando maiores custos e falta de padronização em nossos projetos.

Entretanto com o Reporting Services 2008 tivemos melhoras significativas em termos de gráficos e possibilidades na plataforma Microsoft, ainda na versão 3.5 do .NET foi lançado um pacote com estes recusos de gráficos, disponibilizando-os para o ASP.NET e Win Form.

No .NET 3.5 o Microsoft Chart Controls era disponibilizado separado, por download que poderia ser feito em:

http://www.microsoft.com/downloads/en/details.aspx?FamilyId=130F7986-BF49-4FE5-9CA8-910AE6EA442C&displaylang=en#QuickDetails

Com o Visual Studio 2010 e o .NET Framework 4, este recuso já é disponibilizado nativamente.

Entre os diversos tipos de gráficos disponíveis escolhi o Gráfico de barras para utilizar como exemplo:

Vou fazer um gráfico de barras com os seguintes valores de números de acessos:

List<Acesso> acessos = new List<Acesso>();
acessos.Add(new Acesso { valor = 300, data = "01/08/2010"});
acessos.Add(new Acesso { valor = 340, data = "03/08/2010"});
acessos.Add(new Acesso { valor = 231, data = "04/08/2010"});
acessos.Add(new Acesso { valor = 500, data = "02/08/2010"});

 

Agora vou adicionar o controle de Gráfico na minha página, e customizar algumas propriedades nele:

1) Title

  • ShadowColor: cor da sombra do texto
  • Font: estilo do texto
  • ShadowOffset: deslocamento da sobra to texto
  • Text: texto do titulo
  • ForeColor: cor do texto

2)Legends

  • Enable: abilita/desabilita as legendas

3)BorderSkin

  • SkinStyle: estilo da borda do gráfico

4)ChartArea

  • ChartArea: local para adicionar areas ao gráfico e customizar a exibição dos dados
  • Area3DSyle: customização para a area do gráfico ser exibida em 3d
  • AxisY: customização para o eixo Y do gráfico
  • AxixX: customização para o eixo X do gráfico

Após estas customizações temos o seguinte controle na página:

<asp:Chart ID="Chart1" runat="server">
<Titles>
    <asp:Title ShadowColor="32, 0, 0, 0"
    Font="Trebuchet MS, 14.25pt, style=Bold" ShadowOffset="3"
    Text="Acessos ao Site" ForeColor="26, 59, 105">
    </asp:Title>
</Titles>
<Legends>
    <asp:Legend Enabled="false" >
    </asp:Legend>
</Legends>
<BorderSkin SkinStyle="Emboss"></BorderSkin>
<ChartAreas>
    <asp:ChartArea Name="ChartArea1"
    BorderColor="64, 64, 64, 64" BackSecondaryColor="Transparent"
    BackColor="64, 165, 191, 228" ShadowColor="Transparent"
    BackGradientStyle="TopBottom">
        <Area3DStyle Rotation="10" Perspective="10"
         Enable3D="True" Inclination="15" IsRightAngleAxes="False"
            WallWidth="0" IsClustered="False" />
        <AxisY LineColor="64, 64, 64, 64">
            <LabelStyle Font="Trebuchet MS, 8.25pt, style=Bold" />
            <MajorGrid LineColor="64, 64, 64, 64" />
        </AxisY>
        <AxisX LineColor="64, 64, 64, 64">
            <LabelStyle Font="Trebuchet MS, 8.25pt, style=Bold" />
            <MajorGrid LineColor="64, 64, 64, 64" />
        </AxisX>
    </asp:ChartArea>
</ChartAreas>
</asp:Chart>

Com a estrutura do controle montada podemos adicionar Séries de dados (Series) com os valores em cada uma (Points). Lembrando que isso pode ser feito na página, e também, como nesse exemplo adicionado dinamicamente.

Neste exemplo vou adicionar os dados a partir de uma coleção de Acessos.

Series series = new Series();
series.ChartArea = "ChartArea1";
series.Name = "Series1";
series.Color = System.Drawing.ColorTranslator.FromHtml("#4B6C9E");
series.BorderColor = System.Drawing.ColorTranslator.FromHtml("#3A4F63");

foreach (var item in acessos)
{
    series.Points.Add(new DataPoint {
        YValues = new double[] { item.valor },
        ToolTip = item.data,
        AxisLabel = item.data });
}
Chart1.Series.Add(series);

Como resultado do exemplo teremos um grafico

 

Este post teve como finalidade apresentar um pouco do .NET Chart Controls, todos os recursos e possibilidades do Chart Controls pode ser encontrado em:

http://code.msdn.microsoft.com/mschart

Estou a disposição para dúvidas, criticas e sugestões.

Muito obrigado

Rodolfo

ASP.NET