Web应用构建前从Azure App Configuration获取配置的正确方式
解决方案:绕开BuildServiceProvider,直接从配置系统绑定实例
你现在的问题核心是提前构建ServiceProvider导致单例服务重复实例化,但其实完全不需要走DI容器拿配置——所有配置源(包括Azure App Configuration)都已经加载到builder.Configuration里了,直接从配置节点绑定Settings实例即可,彻底避免BuildServiceProvider的副作用。
具体修改步骤
- 删除通过
BuildServiceProvider获取IOptions<Settings>的代码块 - 直接从
builder.Configuration中提取对应配置节点,绑定到Settings对象 - 若后续代码仍需通过DI获取
IOptions<Settings>,可保留配置注册逻辑不影响现有使用
修改后的完整代码
var builder = WebApplication.CreateBuilder(args); const string JSON = "json"; var appSettingsKey = CONSTANTS.APP.SETTINGS.APPSETTINGS.ToLower(); // 加载本地配置文件与环境变量 builder.Configuration.AddJsonFile($"{appSettingsKey}.{JSON}", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile($"{appSettingsKey}.{builder.Environment.EnvironmentName}.{JSON}", optional: true, reloadOnChange: true); builder.Configuration.AddEnvironmentVariables(); // 集成Azure App Configuration builder.Configuration.AddAzureAppConfiguration(options => options.Connect(builder.Configuration.GetConnectionString(CONSTANTS.APP.SETTINGS.APP_CONFIGURATION_CONNECTION_STRING)) .Select(CONSTANTS.APP.SETTINGS.EQUINOX_SETTINGS_KEY_FILTER, CONSTANTS.APP.SETTINGS.EQUINOX_SETTINGS_LABEL_FILTER) .ConfigureRefresh(refresh => refresh.Register($"{CONSTANTS.APP.SETTINGS.EQUINOX_SETTINGS_PREFIX}:{CONSTANTS.APP.SETTINGS.SENTINEL_KEY}", refreshAll: true)) .UseFeatureFlags()); // 直接从配置系统绑定Settings实例,无需构建ServiceProvider var settingsSection = builder.Configuration.GetSection(CONSTANTS.APP.SETTINGS.EQUINOX_SETTINGS_PREFIX); var settings = settingsSection.Get<Settings>() ?? throw new InvalidOperationException("无法加载Settings配置"); // 保留IOptions注册,供后续DI场景使用(可选) builder.Services.Configure<Settings>(settingsSection); // 正常使用Settings实例初始化Serilog、Orleans等服务 builder.Host.UseSerilog((hostBuilderContext, services, configuration) => { configuration.ConfigureLogging(CONSTANTS.CLUSTER.EQUINOX.ToUpper()); configuration.AddApplicationInsightsLogging(services, hostBuilderContext.Configuration, settings); }); builder.UseOrleans(settings); builder.AddServices(settings); var app = builder.Build();
为什么这种方式可行
- 所有配置源(本地JSON、环境变量、Azure App Configuration)添加完成后,
builder.Configuration已经完成了配置的加载、合并与解析,直接通过GetSection就能拿到完整的配置数据 - 绑定
Settings实例完全不依赖DI容器,从根源上避免了提前构建ServiceProvider导致的单例重复实例化问题 - 若后续业务代码需要通过DI获取
IOptions<Settings>,保留builder.Services.Configure<Settings>(settingsSection)即可,不影响原有逻辑
内容的提问来源于stack exchange,提问作者invernomuto
相关产品推荐
相关产品推荐

