ASP.NET 到 ASP.NET Core 增量 IHttpModule 迁移

模块是实现 IHttpModule 的类型,用于在 ASP.NET Framework 中挂钩到各种事件的请求管道中。 在 ASP.NET Core 应用程序中,最好将这些模块迁移到中间件。 但是,有时无法执行此操作。 为了支持需要模块且无法移动到中间件的迁移方案,System.Web 适配器支持将它们添加到 ASP.NET Core。

IHttpModule 示例

为了支持模块,必须提供一个 HttpApplication 实例。 如果未使用自定义 HttpApplication,则会将模块添加到默认值中。 系统会注册并运行自定义应用程序(包括 Application_Start)中声明的对应事件。

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

Global.asax 迁移

此基础结构可用于按需迁移 Global.asax 的使用情况。 Global.asax 的源是一个自定义 HttpApplication,该文件可以包含在 ASP.NET Core 应用程序中。 它已被命名为 Global,因此可以使用以下代码来注册:

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

只要 ASP.NET Core 支持其中的逻辑,就可以使用此方法将对 Global.asax 的依赖增量迁移到 ASP.NET Core。

身份验证/授权事件

为了在所需时间运行身份验证和授权事件,应使用以下模式:

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

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

如果未执行此操作,事件仍将运行。 但是,它将在调用 .UseSystemWebAdapters() 期间进行。

HTTP 模块池

已将 ASP.NET Framework 中的模块和应用程序分配给请求,因此每个请求都需要一个新实例。 但是,由于创建成本高昂,因此使用 ObjectPool<T> 对其执行池化操作。 若要自定义 HttpApplication 实例的实际生存期,可以使用自定义池:

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

其他资源