Análise Técnica do Modelo de Pipeline no ASP.NET

O modelo de pipeline no ASP.NET representa uma abstração fundamental para o tratamento de requisições HTTP em aplicações web baseadas no framwork .NET. Este modelo define a sequência de eventos e componentes pelos quais uma requisição passa, desde a sua recepção pelo servidor até a geração da resposta final.

Quando um cliente, como um navegador ou HttpClient, envia uma requisição para uma aplicação ASP.NET, o fluxo é iniciado com a resolução do nome de domínio pelo DNS, que retorna o endereço IP e a porta corretos. O serviço de escuta HttpSys, integrado ao IIS, recebe a requisição encaminhada. Com base na extensão do arquivo da requisição, o IIS redireciona o processamento para o módulo ISAPI adequado, como o aspnet_isapi.dll para aplicações .NET, configurado via Mapeamento de Manipuladores.

Ao atingir o módulo ISAPI, a requisição é encapsulada em um objeto HttpWorkerRequest e passada para o método HttpRuntime.ProcessRequest. Dentro deste método, uma instância de HttpApplication é criada pelo HttpApplicationFactory, utilizando o contexto da requisição. A partir deste ponto, o ciclo de vida controlado pelo pipeline efetivamente inicia, permitindo extensões e personalizações pelo desenvolvedor.

A classe HttpApplication serve como o ponto central do pipeline, expondo uma série de eventos que são acionados sequencialmente para cada requisição HTTP. Estes eventos abrangem desde o início da requisição até a finalização, permitindo a inserção de lógica em diversas fases do processamento. A estrutura de eventos segue padrões de design como o Princípio Aberto/Fechado e o padrão Observador, utilizando delegações (callbacks) para desacoplar a lógica fixa da lógica extensível.

public class HttpApplication : IComponent, IDisposable, IHttpAsyncHandler, IHttpHandler
{
    public event EventHandler InicioRequisicao;
    public event EventHandler AutenticacaoRequisicao;
    public event EventHandler PosAutenticacao;
    public event EventHandler AutorizacaoRequisicao;
    public event EventHandler PosAutorizacao;
    public event EventHandler ResolverCache;
    public event EventHandler PosResolverCache;
    public event EventHandler PosMapeamentoHandler;
    public event EventHandler ObterEstado;
    public event EventHandler PosObterEstado;
    public event EventHandler PreExecucaoHandler;
    public event EventHandler PosExecucaoHandler;
    public event EventHandler LiberarEstado;
    public event EventHandler PosLiberarEstado;
    public event EventHandler AtualizarCache;
    public event EventHandler PosAtualizarCache;
    public event EventHandler LogRequisicao;
    public event EventHandler PosLogRequisicao;
    public event EventHandler FimRequisicao;
}

Para extender o comportamento do pipeline, o ASP.NET fornece o conceito de HttpModule. Um módulo HTTP implementa a interface IHttpModule e se inscreve nos eventos da classe HttpApplication. Como estes eventos são executados para cada requisição, os módulos são ideais para funcionalidades globais, como compressão de resposta, monitoramento de desempenho ou validação de segurança.

Cnosidere um exemplo que implementa a compressão de resposta usando GZIP ou DEFLATE, dependendo dos cabeçalhos da requisição:

internal class ModuloCompressao : IHttpModule
{
    public void Dispose() { }

    public void Init(HttpApplication aplicativo)
    {
        aplicativo.InicioRequisicao += AoInicioRequisicao;
    }

    private void AoInicioRequisicao(object remetente, EventArgs args)
    {
        var app = (HttpApplication)remetente;
        string aceitarCodificacao = app.Context.Request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(aceitarCodificacao)) return;

        aceitarCodificacao = aceitarCodificacao.ToUpperInvariant();

        if (aceitarCodificacao.Contains("GZIP"))
        {
            app.Context.Response.AppendHeader("Content-encoding", "gzip");
            app.Context.Response.Filter = new GZipStream(
                app.Context.Response.Filter, CompressionMode.Compress);
        }
        else if (aceitarCodificacao.Contains("DEFLATE"))
        {
            app.Context.Response.AppendHeader("Content-encoding", "deflate");
            app.Context.Response.Filter = new DeflateStream(
                app.Context.Response.Filter, CompressionMode.Compress);
        }
    }
}

Este módulo pode ser registrado no arquivo de configuração web.config ou dinamicamente via código, como mostrado a seguir com um atributo de compilação:

[assembly: PreApplicationStartMethod(typeof(RegistroDinamicoModulo), "Registrar")]
public class RegistroDinamicoModulo
{
    public static void Registrar()
    {
        HttpApplication.RegisterModule(typeof(ModuloCompressao));
    }
}

O HttpHandler é o componente responsável pelo processamento final da requisição. Ele implementa a interface IHttpHandler e contém a lógica específica para gerar a resposta, como renderizar uma página ou servir um recurso estático. Diferentes handlers podem ser mapeados para diferentes extensões de arquivo, permitindo o roteamento customizado.

Para ilustrar, crie um handler que processa requisições com a extensão ".cc":

public class ManipuladorCustomizado : IHttpHandler
{
    public bool IsReusable => false;

    public void ProcessRequest(HttpContext contexto)
    {
        string dataHora = DateTime.Now.ToString("HH:mm:ss");
        string corpoResposta = $"Manipulador customizado processou requisição às {dataHora}";
        contexto.Response.Write(corpoResposta);
    }
}

No arquivo de configuração, associe este handler à extensão ".cc":

<system.webServer>
    <handlers>
        <add name="ManipuladorCC" path="*.cc" verb="*"
             type="SeuNamespace.ManipuladorCustomizado, SeuAssembly"
             preCondition="integratedMode" />
    </handlers>
</system.webServer>

Componentes como MvcHandler ou HttpControllerHandler são implementações especializadas de HttpHandler dentro dos frameworks MVC e Web API, demonstrando a extensibilidade do pipeline central do ASP.NET.

Tags: ASP.NET Pipeline HttpApplication HttpModule HttpHandler

Publicado em 6-22 00:59