Partilhar via


Migração incremental de IHttpModule do ASP.NET para o ASP.NET Core

Módulo são tipos que implementam IHttpModule e são usados no ASP.NET Framework para se conectar ao pipeline de solicitações em vários eventos. Em um aplicativo ASP.NET Core, o ideal é que eles sejam migrados para o middleware. No entanto, há ocasiões em que isso não pode ser feito. Para dar suporte a cenários de migração nos quais os módulos são necessários e não podem ser migrados para o middleware, os adaptadores System.Web dão suporte à adição deles ao ASP.NET Core.

Exemplo de IHttpModule

Para dar suporte a módulos, uma instância de HttpApplication deve estar disponível. Se nenhum HttpApplication personalizado for usado, um padrão será usado para adicionar os módulos. Os eventos declarados em um aplicativo personalizado (incluindo Application_Start) serão registrados e executados adequadamente.

using System.Web;
using Microsoft.AspNetCore.OutputCaching;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSystemWebAdapters()
    .AddHttpApplication<MyApp>(options =>
    {
        // Size of pool for HttpApplication instances. Should be what the expected concurrent requests will be
        options.PoolSize = 10;

        // Register a module (optionally) by name
        options.RegisterModule<MyModule>("MyModule");
    });

// Only available in .NET 7+
builder.Services.AddOutputCache(options =>
{
    options.AddHttpApplicationBasePolicy(_ => new[] { "browser" });
});

builder.Services.AddAuthentication();
builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthenticationEvents();

app.UseAuthorization();
app.UseAuthorizationEvents();

app.UseSystemWebAdapters();
app.UseOutputCache();

app.MapGet("/", () => "Hello World!")
    .CacheOutput();

app.Run();

class MyApp : HttpApplication
{
    protected void Application_Start()
    {
    }

    public override string? GetVaryByCustomString(System.Web.HttpContext context, string custom)
    {
        // Any custom vary-by string needed

        return base.GetVaryByCustomString(context, custom);
    }
}

class MyModule : IHttpModule
{
    public void Init(HttpApplication application)
    {
        application.BeginRequest += (s, e) =>
        {
            // Handle events at the beginning of a request
        };

        application.AuthorizeRequest += (s, e) =>
        {
            // Handle events that need to be authorized
        };
    }

    public void Dispose()
    {
    }
}

Migração do Global.asax

Essa infraestrutura pode ser usada para migrar o uso de Global.asax, se necessário. A fonte de Global.asax é um HttpApplication personalizado e o arquivo pode ser incluído em um aplicativo ASP.NET Core. Como ele é denominado Global, o código a seguir pode ser usado para registrá-lo:

builder.Services.AddSystemWebAdapters()
    .AddHttpApplication<Global>();

Desde que a lógica dentro dele esteja disponível no ASP.NET Core, essa abordagem pode ser usada para migrar de forma incremental a dependência de Global.asax para o ASP.NET Core.

Eventos de autenticação/autorização

Para que os eventos de autenticação e autorização sejam executados no momento desejado, o seguinte padrão deve ser usado:

app.UseAuthentication();
app.UseAuthenticationEvents();

app.UseAuthorization();
app.UseAuthorizationEvents();

Se isso não for feito, os eventos ainda serão executados. No entanto, será durante a chamada de .UseSystemWebAdapters().

Agrupamento de módulos HTTP

Como os módulos e aplicativos no ASP.NET Framework foram atribuídos a uma solicitação, é necessária uma nova instância para cada solicitação. Entretanto, como a criação desses módulos pode ser cara, eles são agrupados usando ObjectPool<T>. Para personalizar o tempo de vida real das instâncias HttpApplication, um pool personalizado pode ser usado:

builder.Services.TryAddSingleton<ObjectPool<HttpApplication>>(sp =>
{
    // Recommended to use the in-built policy as that will ensure everything is initialized correctly and is not intended to be replaced
    var policy = sp.GetRequiredService<IPooledObjectPolicy<HttpApplication>>();

    // Can use any provider needed
    var provider = new DefaultObjectPoolProvider();

    // Use the provider to create a custom pool that will then be used for the application.
    return provider.Create(policy);
});

Recursos adicionais