Caching via Providers

by Israel Aece 16. November 2009 13:08

Assim como o membership, roles, profile, webparts ou health monitoring, a versão 4.0 do ASP.NET também permitirá trabalhar com o caching seguindo essa mesma arquitetura, ou seja, através de provider models. Com isso, teremos uma maior flexibilidade para elegermos o nosso repositório de caching, que nem sempre será a memória do próprio servidor onde a aplicação está hospedada. Provavelmente será através deste recurso que a Microsoft irá acoplar o "Velocity" ao pipeline do ASP.NET.

Para customizar, tudo o que precisamos fazer é criar uma classe que herde da classe abstrata OutputCacheProvider, e sobrescrever os seus métodos autoexplicativos: Add, Get, Remove e Set, assim como é mostrado abaixo.

public class TextCacheProvider : OutputCacheProvider
{
    private static readonly string PATH;

    static TextCacheProvider()
    {
        PATH = HttpContext.Current.Server.MapPath("~/CachedPages/");
    }

    public override object Add(string key, object entry, DateTime utcExpiry) { } 

    public override object Get(string key) { }

    public override void Remove(string key) { }

    public override void Set(string key, object entry, DateTime utcExpiry) { }
}

Depois desta classe criada, que seguirá as regras de caching customizadas, precisamos configurá-la para poder ser utilizada, e para isso recorremos ao arquivo Web.config. Tudo o que precisamos fazer para que essa nova classe funcione, é acoplá-la a execução, definindo-a como sendo o provider padrão de caching. O trecho de código abaixo ilustra essa configuração:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
    <caching>
      <outputCache defaultProvider="TextCacheProvider" enableOutputCache="true">
        <providers>
          <clear/>
          <add name="TextCacheProvider" type="TextCacheProvider"/>
        </providers>
      </outputCache>
    </caching>
</configuration>

E se desejar escolher, em tempo de execução, um dos providers de acordo com uma condição específica, você poderá fazer isso através do método GetOutputCacheProviderName, que é exposto pela classe HttpApplication (Global.asax), e retorna uma string que representá o provider a ser utilizado.

Tags: , ,

ASP.NET

Internals - Proxy de serviços WCF

by Israel Aece 17. September 2009 08:18

Para aqueles que desejam consumir um serviço (WCF ou não) através da infraestrutura do WCF que existe do lado do cliente, existem duas opções para referenciá-lo na aplicação cliente, e cada uma dessas opções fornecem suas vantagens e desvantagens. A finalidade deste artigo é tentar descrever como as coisas funcionam nos bastidores, para conseguirmos tirar o melhor proveito disso.

A mais comum entre as formas de acesso um serviço, é a geração do proxy de forma automática, que através da IDE do Visual Studio ou do utilitário svcutil.exe, basta que eu informe o endereço do documento WSDL, e uma classe será criada com toda a estrutura necessária para gerenciar e invocar operações do serviço remoto. Nesta opção, todos os tipos que, eventualmente, o serviço exponha, serão automaticamente reconstruídos do lado do cliente, para que o mesmo seja capaz de enviar e/ou receber tais tipos.

Entre os tipos que são reconstruídos do lado do cliente, uma Interface é criada representando o contrato do serviço, contendo todas as operações que ele fornece. Além disso, uma classe também é criada, herdando da classe abstrata ClientBase<TChannel>. Essa classe é a que conhecemos como "proxy". Ao herdar de ClientBase<TChannel>, o parâmetro genérico TChannel é substituído pela Interface que representa o contrato do serviço, que como vimos, foi reconstruída do lado do cliente. Além disso, a Interface do contrato do serviço também é implementada nesta classe, ou seja, ao instanciar o proxy, veremos os métodos que foram disponibilizados no serviço. Durante o tempo de execução, ao invocar esses métodos locais, o WCF encaminhará a requisição para o serviço.

Essa classe nada mais é do que um wrapper, que visa facilitar a vida de quem consome o serviço fornecendo, além dos métodos que refletem as suas operações, métodos que gerenciam a vida do canal de comunicação, tais como Open, Close, Abort, etc. Ao criar a instância desta classe ou descartá-la, uma série de tarefas custosas e complexas são realizadas, tais como: carregar as configurações do arquivo de configuração, criar toda a árvore de tipos que descreve o serviço, construção da channel stack (a complexidade depende das funcionalidades habilitadas) e o descarte dos recursos que a mesma utiliza para efetuar a comunicação.

Internamente essa classe mantém/referencia um objeto do tipo ChannelFactory<TChannel>, que é uma factory responsável por criar e configurar, efetivamente, o canal de comunicação entre o cliente e o serviço. Antes do .NET Framework 3.5 + SP1, essa classe era instanciada uma única vez, e depois é mantida viva durante a instância do proxy. Na versão mais recente, não existe mais essa afinidade, ou seja, a instância da ChannelFactory<TChannel> é mantida em nível do AppDomain, e sendo assim, mesmo que você crie e descarte o proxy a todo o momento, grande parte do processo complexo e custoso, será mantido e reutilizado independentemente de quantas instâncias do proxy você venha a criar, gerando uma espécie de cache.

Esse cache melhora consideravelmente o custo de inicialização, que na maioria das vezes, é sempre igual. Esse cache trabalha no formato MRU (most recently used), e está "limitado" à 32 objetos, e quando essa capacidade for atingida, os últimos vão sendo removidos. A cada instância do proxy, antes do WCF efetivamente criar a instância da classe ChannelFactory<TChannel> correspondente, ele interroga o cache a procura deste objeto (que atenda a essas mesmas características), e caso o encontre, evitará a criação de um novo.

Um cuidado especial que se deve ter é com relação as versões que temos no cache. O construtor do proxy possui vários overloads, e os objetos que estão colocados no cache são versionados de acordo com esses parâmetros. Aqueles overloads que não aceitam um Binding como parâmetro, seguramente, objetos que estão no cache serão reutilizados, já que os demais parâmetros são imutáveis. Quando um Binding é passado como parâmetro para um dos construtores, o caching será desabilitado, já que não há como garantir que as informações definidas na instância do binding serão sempre as mesmas. A mesma regra se aplica quando você acessa as propriedades ChannelFactory, Endpoint e ClientCredentials do proxy antes do canal de comunicação ser criado e aberto.

Voltando as formas que temos de invocar um serviço, a segunda possibilidade é utilizar o ChannelFactory<TChannel> diretamente, sem criar o proxy por algumas das ferramentas que vimos acima. Essa técnica nos permite ter um maior controle do caching, já que essa funcionalidade ficará sob nossa responsabilidade. Você pode manter a factory em algum ponto do teu código, e quando precisar de um novo canal de comunicação com as mesmas configurações, basta invocar o método CreateChannel, que ele te retorna uma instância configurada. O ponto negativo desta técnica, é que o cliente já tem que, de alguma forma, conhecer os tipos e contratos que são expostos pelo serviço, cenário comum quando utilizamos assemblies compartilhados. O código abaixo ilustra como podemos proceder para fazer isso:

ChannelFactory<IContrato> factory =
    new ChannelFactory<IContrato>(new NetTcpBinding(), "net.tcp://localhost:3922/srv");

IContrato proxy = factory.CreateChannel();
Console.WriteLine(proxy.Ping("Israel"));

Além de você já precisar conhecer os tipos, para invocar qualquer método que gerencie a vida do proxy (Open, Close, Abort, etc.), você precisará converter explicitamente para ICommunicationObject. E, para finalizar, quando não precisar mais da factory, tudo o que precisa fazer é também invocar o seu método Close, que descarta todos os recursos custosos que ela armazena. O exemplo abaixo ilustra como podemos proceder para encerrar o proxy e, eventualmente, a factory:

((ICommunicationObject)proxy).Close();

//Eventualmente
factory.Close();

Conclusão: Ambas técnicas tem seus pontos positivos e negativos. Muito do que vimos neste artigo, acaba sendo gerenciado de forma automática pelo WCF, mas conhecendo alguns detalhes internos como estes, nos permite identificar problemas de performance que, eventualmente, podemos estar sofrendo.

Tags: , , ,

WCF

Core Services no ASP.NET 4.0

by Israel Aece 24. March 2009 14:38

Além de algumas novidades que já foram reportadas neste post, o ASP.NET 4.0 trará ainda uma série de funcionalidades muito interessantes e, entre elas, teremos:

OutputCaching Extensível

Quando utilizamos o OutputCaching em uma página, a primeira requisição a executará, e antes de devolver o conteúdo para o cliente, o resultado é armazenado na memória do servidor Web, e com isso, futuras requisições utilizarão esse conteúdo ao invés de reprocessar a página completamente. O ASP.NET 4.0 fornece uma forma altamente flexível para conseguirmos customizar o repositório de caching trabalhando com providers, assim como já acontece nas principais funcionalidades do ASP.NET atual.

Auto-Start de Aplicações

Todos sabemos que as aplicações ASP.NET tem um delay na primeira requisição, que se deve ao fato de efetuar a compilação da mesma. A partir do ASP.NET 4.0, em conjunto com o IIS 7.5, teremos uma funcionalidade chamada de auto-start. Ao configurar esta funcionalidade em uma aplicação, o IIS enviará uma mensagem ao ASP.NET para que a sua aplicação faça o processo necessário para deixá-la pronta para ser consumida. Tudo isso ocorre no momento em que o IIS/AppPool ainda não aceita requisições.

O mais interessante é que ainda podemos interceptar este evento, implementando o método Preload da Interface IProcessHostPreloadClient. Nele podemos fazer outras "pré-inicializações" que antes eram feitas sob demanda.

Redirecionamento Permanente

Como já comentado aqui, agora teremos um método chamado RedirectPermanent que efetuará esse tipo de redirecionamento.

Compressão das variáveis de Sessão

Quando utilizamos variáveis de sessão, elas são armazenadas na memória do servidor onde a aplicação está sendo executada (In-Process). Além disso, temos duas outras possibilidades que é o armazenamento diretamente no SQL Server ou um servidor exclusivo para o armazenamento das variáveis sessão (Out-of-Process). Nestas duas últimas opções, há um overhead extra, que ocorre justamente porque o objeto responsável que armazena as informações, deverá ser serializado antes de enviado para o destino remoto.

Dependendo do que é armazenado dentro das variáveis de sessão, esse processo pode custar muito caro, tanto em termos de comunicação quanto em termos de memória ou espaço físico. A partir do ASP.NET 4.0, o elemento sessionState irá possuir um novo atributo chamado compressionEnabled. Ao definí-lo como True, o ASP.NET fará o processo necessário para comprimir e descomprimir os dados, utilizando a classe GZipStream.

Para aqueles que quiserem mais informações sobre as novas funcionalidades, consulte este documento.

Tags: ,

ASP.NET

Customizando o OutputCache

by Israel Aece 20. November 2008 08:50

Um dia desses um colega me perguntou como customizar, ou melhor, como variar o OutputCaching de uma página para cada usuário da aplicação. Entre as opções que a diretiva @OutputCache fornece, temos a opção VaryByCustom, especificando como valor deste atributo uma string qualquer, com a finalidade de definirmos uma informação, que indicará como proceder para capturar a "chave" que será utilizada pelo runtime, para determinar se já existe ou não uma versão do cache. Abaixo está a configuração desta diretiva:

<%@ OutputCache Duration="60" VaryByCustom="UserName" VaryByParam="none" %>

Quando utilizamos esta técnica, devemos sobrescrever o método GetVaryByCustomString da classe HttpApplication (leia-se Global.asax) e, lá colocar o código que irá retornar a string que servirá de "chave", para que o ASP.NET use-a para determinar se já existe ou não uma versão para ela. No nosso caso, a finalidade é criar uma versão de caching para cada usuário, portanto, temos o seguinte código:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if(custom == "UserName" && context.User.Identity.IsAuthenticated)
        return context.User.Identity.Name;

    return base.GetVaryByCustomString(context, custom);
}

Tags: ,

ASP.NET

Evitando a remoção do Cache

by Israel Aece 14. August 2008 11:13

Thomas Marquardt mostra aqui uma nova funcionalidade da API de Caching do ASP.NET 3.5. Basicamente a idéia aqui é interceptar o momento antes do item ser efetivamente removido do cache.

Tags: ,

ASP.NET

Distributed Caching

by Israel Aece 4. June 2008 12:36

Demorou, mas está saindo...

Tags: ,

.NET Framework

Outputcache - CacheProfile

by Israel Aece 27. April 2006 09:16

Estou trabalhando em um projeto ASP.NET 2.0 e, como algumas páginas estavam requerendo o uso de Outputcache, para cada uma dessas páginas estava ajustando o mesmo valor de segundos no atributo Duration e também especificando algumas outras propriedades desta mesma diretiva, customizando assim, o cache da forma que necessitava.

Mas em um certo momento me perguntei: e se esses valores e condições mudarem? Sim, terei que ir a cada página e especificar tudo novamente. Foi nesse momento que recorri a documentação do .NET Framework e encontrei o elemento outputCacheProfiles que é especificado dentro do arquivo Web.Config.

Com isso, ao invés de especificar os mesmos valores em cada página ASPX, eu criei uma "profile" dentro do Web.Config e passo a utilizar este "profile" nas páginas ASPX. Um exemplo do uso é mostrado abaixo:

[ Web.Config ]
<outputCacheSettings>
  <outputCacheProfiles>
    <add name = "PaginasEmCache"
      varyByParam = "TituloID"
      enabled = "true"
      duration = "180" />
  </outputCacheProfiles>
</outputCacheSettings>

[ *.ASPX ]
<%@ OutputCache CacheProfile="PaginasEmCache" %>

Tags: ,

ASP.NET

Post Cache Substitution

by Israel Aece 12. February 2006 09:27

Quando colocamos uma determinada página em OutputCache nas versões 1.x do ASP.NET, tínhamos/temos problemas quando existem nesta página, regiões dinamicas que, devem ser sempre atualizadas quando um Refresh ou PostBack acontecer.

Com este cenário, ou teríamos que optar por não deixar a página em OutputCache, ou criar UserControls (arquivos ASCX) para habilitar o Fragment Caching e assim, atualizar essas informações dinamicas. No ASP.NET 2.0 foi introduzido um novo conceito chamado de Post Cache Substitution. Trata-se de um controle chamado Substitution, que temos à disposição na ToolBox do Visual Studio .NET 2005. Devemos arrastá-lo para o local da página onde o conteúdo será dinamico e, através da propriedade MethodName do mesmo, apontamos para um método estático que, obrigatoriamente deverá estar de acordo com o delegate HttpResponseSubstitutionCallback. Este será o método qual o ASP.NET executará sempre.

Abaixo é exibido um exemplo simples que ilustra o funcionamento desta nova feature:

<%@ OutputCache Duration="60" VaryByParam="none" %>
....
<asp:Substitution
     ID="Substitution1" 
     runat="server" 
     MethodName="GetCurrentDateTime" />

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

E no CodeBehind:

    protected void Page_Load(object sender, EventArgs e)
    {
        this.Label1.Text = DateTime.Now.ToString();
    }

    public static string GetCurrentDateTime(HttpContext ctx)
    {
        return DateTime.Now.ToString();
    }

Esse código fará com que a página fique em OutputCache durante 60 segundos, porém a região da página que é determinada pelo controle Substitution, sempre será atualizada.

Tags: ,

ASP.NET

Powered by BlogEngine.NET 1.5.0.0
Theme by Mads Kristensen

Sobre

Meu nome é Israel Aece e sou especialista em tecnologias de desenvolvimento Microsoft, atuando como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. [ Mais ]

Twitter

Host