You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.Net Core自动加载初始化器:无需Startup获取ApplicationBuilder的疑问

解决自动加载初始化器并管理ApplicationBuilder的问题

看起来你已经搭建了一个不错的服务注册自动化框架,核心痛点是如何把IApplicationBuilderInitializer的自动加载也整合进去,同时避免在Startup/Program里写一堆手动调用的代码。我来一步步帮你完善这个方案:

核心问题拆解

你当前的ServiceCollectionInitializerRegistry只处理了服务集合的初始化,但还没覆盖应用构建器(中间件配置)的自动执行。另外,原代码里先构建ServiceProvider再执行服务初始化的顺序有问题——初始化器新增的服务不会被已构建的Provider识别,得调整顺序。

解决方案:统一注册表+自动发现+扩展方法简化调用

第一步:完善初始化器接口(如果还没定义的话)

public interface IServiceCollectionInitializer
{
    void Initialize(IConfiguration configuration, IServiceCollection services, ILogger logger);
}

public interface IApplicationBuilderInitializer
{
    void Initialize(IConfiguration configuration, IApplicationBuilder builder, ILoggerFactory loggerFactory);
}

第二步:创建统一的初始化器注册表

这个类会同时管理两种初始化器的自动发现和执行,还会修正服务注册的顺序问题:

using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class InitializerRegistry
{
    private readonly IList<IServiceCollectionInitializer> _serviceInitializers = new();
    private readonly IList<IApplicationBuilderInitializer> _appBuilderInitializers = new();
    private readonly IServiceCollection _services;
    private IServiceProvider? _serviceProvider;

    public InitializerRegistry(IServiceCollection services)
    {
        _services = services;
    }

    // 手动添加服务初始化器
    public InitializerRegistry WithServiceInitializers(params IServiceCollectionInitializer[] initializers)
    {
        if (initializers.Any())
            _serviceInitializers.AddRange(initializers);
        return this;
    }

    // 从入口程序集自动发现服务初始化器(支持依赖注入)
    public InitializerRegistry WithAssemblyServiceInitializers()
    {
        var entryAssembly = Assembly.GetEntryAssembly();
        if (entryAssembly == null) return this;

        var initializerTypes = entryAssembly.GetTypes()
            .Where(t => typeof(IServiceCollectionInitializer).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

        // 先把初始化器注册为服务,支持构造函数依赖
        foreach (var type in initializerTypes)
            _services.AddSingleton(typeof(IServiceCollectionInitializer), type);

        // 从临时Provider中解析初始化器
        var tempProvider = _services.BuildServiceProvider();
        _serviceInitializers.AddRange(tempProvider.GetServices<IServiceCollectionInitializer>());

        return this;
    }

    // 手动添加应用构建器初始化器
    public InitializerRegistry WithAppBuilderInitializers(params IApplicationBuilderInitializer[] initializers)
    {
        if (initializers.Any())
            _appBuilderInitializers.AddRange(initializers);
        return this;
    }

    // 从入口程序集自动发现应用构建器初始化器(支持依赖注入)
    public InitializerRegistry WithAssemblyAppBuilderInitializers()
    {
        var entryAssembly = Assembly.GetEntryAssembly();
        if (entryAssembly == null) return this;

        var initializerTypes = entryAssembly.GetTypes()
            .Where(t => typeof(IApplicationBuilderInitializer).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

        // 先注册为服务
        foreach (var type in initializerTypes)
            _services.AddSingleton(typeof(IApplicationBuilderInitializer), type);

        // 临时解析
        var tempProvider = _services.BuildServiceProvider();
        _appBuilderInitializers.AddRange(tempProvider.GetServices<IApplicationBuilderInitializer>());

        return this;
    }

    // 执行所有服务初始化,构建最终的ServiceProvider
    public void BuildServices()
    {
        var tempProvider = _services.BuildServiceProvider();
        var configuration = tempProvider.GetRequiredService<IConfiguration>();
        var loggerFactory = tempProvider.GetRequiredService<ILoggerFactory>();

        // 先执行所有服务注册
        foreach (var initializer in _serviceInitializers)
        {
            var logger = loggerFactory.CreateLogger(initializer.GetType().FullName);
            initializer.Initialize(configuration, _services, logger);
        }

        // 构建最终的ServiceProvider
        _serviceProvider = _services.BuildServiceProvider();
    }

    // 执行所有应用构建器初始化(中间件配置)
    public void BuildApplication(IApplicationBuilder app)
    {
        if (_serviceProvider == null)
            throw new InvalidOperationException("请先调用BuildServices()完成服务初始化");

        var configuration = _serviceProvider.GetRequiredService<IConfiguration>();
        var loggerFactory = _serviceProvider.GetRequiredService<ILoggerFactory>();

        foreach (var initializer in _appBuilderInitializers)
            initializer.Initialize(configuration, app, loggerFactory);
    }
}

第三步:用扩展方法简化Program.cs调用

为了让整个过程完全自动化,把注册表的调用封装成扩展方法:

public static class InitializerRegistryExtensions
{
    public static WebApplicationBuilder UseInitializerRegistry(this WebApplicationBuilder builder)
    {
        var registry = new InitializerRegistry(builder.Services)
            .WithAssemblyServiceInitializers()
            .WithAssemblyAppBuilderInitializers();
        
        registry.BuildServices();
        // 把注册表存入服务容器,后续构建应用时使用
        builder.Services.AddSingleton(registry);
        return builder;
    }

    public static WebApplication UseInitializerRegistry(this WebApplication app)
    {
        var registry = app.Services.GetRequiredService<InitializerRegistry>();
        registry.BuildApplication(app);
        return app;
    }
}

第四步:在Program.cs中使用

现在你的Program.cs会非常简洁,完全不需要手动处理初始化器:

var builder = WebApplication.CreateBuilder(args);
// 自动加载所有服务初始化器
builder.UseInitializerRegistry();

var app = builder.Build();
// 自动加载所有应用构建器初始化器(中间件)
app.UseInitializerRegistry();

// 剩下的自定义路由/中间件(如果有的话)
app.MapGet("/", () => "Hello World!");

app.Run();

关键细节说明

  1. 服务初始化顺序修正:先执行所有服务初始化器的注册逻辑,再构建最终的ServiceProvider,确保初始化器新增的服务能被容器识别。
  2. 支持依赖注入:自动发现时先把初始化器注册为服务,再从容器中解析,这样初始化器本身的构造函数依赖也能被正确注入。
  3. 完全自动化:只要你的初始化器实现了对应的接口,就会被自动发现和执行,不需要在Startup/Program里手动添加。

内容的提问来源于stack exchange,提问作者Cope

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:32:50