Share via


Migration incrémentielle de IHttpModule d’ASP.NET vers ASP.NET Core

Les modules sont des types qui implémentent IHttpModule et sont utilisés dans l’infrastructure ASP.NET pour la connexion au pipeline de requêtes en réponse à divers événements. Dans une application ASP.NET Core, ceux-ci doivent être migrés dans l’idéal vers un intergiciel. Toutefois, il existe des circonstances où cela n’est pas possible. Dans les scénarios de migration où les modules sont nécessaires alors qu’ils ne peuvent pas être déplacés vers un intergiciel, les adaptateurs System.Web prennent en charge leur ajout à ASP.NET Core.

Exemple de IHttpModule

Pour permettre la prise en charge des modules, une instance de HttpApplication doit être disponible. Si aucun HttpApplication personnalisé n’est utilisé, une instance par défaut est utilisée pour ajouter les modules. Les événements déclarés dans une application personnalisée (notamment Application_Start) sont inscrits et exécutés de manière appropriée.

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()
    {
    }
}

Migration de Global.asax

Cette infrastructure peut être utilisée pour migrer l’utilisation de Global.asax, le cas échéant. La source de Global.asax est un HttpApplication personnalisé, et le fichier peut être inclus dans une application ASP.NET Core. Dans la mesure où il se nomme Global, vous pouvez utiliser le code suivant pour l’inscrire :

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

Tant que la logique qu’elle contient est disponible dans ASP.NET Core, cette approche peut être utilisée pour migrer de manière incrémentielle la dépendance à Global.asax vers ASP.NET Core.

Événements d’authentification/d’autorisation

Pour que les événements d’authentification et d’autorisation s’exécutent au moment souhaité, vous devez utiliser le modèle suivant :

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

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

Dans le cas contraire, les événements s’exécutent tout de même. Toutefois, cela se produira durant l’appel de .UseSystemWebAdapters().

Regroupement de modules HTTP

Dans la mesure où les modules et les applications de l’infrastructure ASP.NET ont été affectés à une requête, une nouvelle instance est nécessaire pour chaque requête. Toutefois, dans la mesure où leur création peut être coûteuse, elles sont groupées à l’aide de ObjectPool<T>. Pour personnaliser la durée de vie réelle des instances de HttpApplication, vous pouvez utiliser un pool personnalisé :

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);
});

Ressources supplémentaires