.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();
关键细节说明
- 服务初始化顺序修正:先执行所有服务初始化器的注册逻辑,再构建最终的
ServiceProvider,确保初始化器新增的服务能被容器识别。 - 支持依赖注入:自动发现时先把初始化器注册为服务,再从容器中解析,这样初始化器本身的构造函数依赖也能被正确注入。
- 完全自动化:只要你的初始化器实现了对应的接口,就会被自动发现和执行,不需要在Startup/Program里手动添加。
内容的提问来源于stack exchange,提问作者Cope
相关产品推荐
相关产品推荐

