Azure Web应用程序门户应用设置读取异常问题求助
问题描述
我有一个托管在Azure上、通过Visual Studio发布的Azure API,希望在Azure门户的应用设置中为不同部署槽的同一键设置不同值,但设置会同步应用到所有部署槽。
该API基于WebApplicationBuilder builder = WebApplication.CreateBuilder(args);创建,我尝试了多种读取配置值的方式:
builder.Configuration["VariableName"];Environment.GetEnvironmentVariable("VariableName");builder.Configuration.GetSection("Values").Get<Details>();
其中Details类定义如下:public class Details { public string VariableName { get; set; } }
我还添加了builder.Configuration.AddEnvironmentVariables();代码,但无论在Program.cs的哪个位置调用,获取到的值始终为null。
异常现象:API运行后处理请求时能成功读取到值——比如在Program.cs早期调用CosmosDbConfig.initialize(builder.Configuration);并赋值apiKey = configuration["VariableName"];,赋值后立即访问apiKey为null,但API接口被调用时却能返回正确的apiKey值。
应用设置在Azure门户的位置:
对应部署槽的「配置」-「应用程序设置」界面,添加的键值对未勾选「部署槽设置」选项。
完整Program.cs代码
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Configuration.AddEnvironmentVariables(); CosmosDbConfig.initialize(builder.Configuration); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => { options.Authority = "placeholder"; options.Audience = "placeholder"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true }; }); builder.Services.AddApplicationInsightsTelemetry(options => { options.ConnectionString = "placeholder"; }); builder.Services.AddScoped<AuthorizationContext>(); builder.Services.AddScoped<DebugContext>(); builder.Services.AddScoped<JwtValidator>(); builder.Services.AddScoped<RequestorContext>(); builder.Services.AddScoped<GetRequestorObjectsFilter>(); builder.Services.AddControllersWithViews(options => { options.Filters.AddService<GetRequestorObjectsFilter>(); }); builder.Services.AddSwaggerGen(c => { string title = builder.Configuration["VariableName"]; c.SwaggerDoc("v1", new OpenApiInfo { Title = title, Version = "v1" }); }); builder.Services.AddAuthorization(); builder.Services.AddMvc(); builder.Services.AddHttpClient(); builder.Services .AddSignalR(hubOptions => { hubOptions.AddFilter<ExceptionHandlingHubFilter>(); }) .AddAzureSignalR(hubOptions => { hubOptions.ConnectionString = "placeholder"; }); builder.Services.AddCors(options => options.AddPolicy("CorsPolicy", policyBuilder => { policyBuilder .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() .WithOrigins("placeholder"); })); builder.Services.AddSingleton(x => { string accountName = "placeholder"; string containerName = "placeholder"; string accountKey = "placeholder"; string blobServiceEndpoint = $"https://{accountName}.blob.core.windows.net"; BlobServiceClient blobServiceClient = new BlobServiceClient(new Uri(blobServiceEndpoint), new StorageSharedKeyCredential(accountName, accountKey)); BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName); return blobContainerClient; }); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } LoggerFactoryProvider.LoggerFactory = app.Services.GetRequiredService<ILoggerFactory>(); app.UseMiddleware<ExceptionHandlingMw>(); app.UseMiddleware<AuthorizationMw>(); app.UseSwagger(); app.UseCors("CorsPolicy"); app.UseHttpsRedirection(); app.UseRouting(); app.UseFileServer(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapHub<MyHub>($"/{SignalRHubData.hubName}"); }); app.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); await ProceduresSetup.run(); app.Run();
解决方案
1. 解决部署槽配置全局同步问题
Azure应用服务中,只有**勾选「部署槽设置」**的配置项才会被标记为「槽专属」,仅对当前部署槽生效;未勾选的配置属于「槽无关」,修改后会同步到所有部署槽。
操作步骤:
- 进入目标部署槽的「配置」-「应用程序设置」页面
- 找到目标键值对,点击编辑按钮
- 勾选「部署槽设置」选项,保存更改即可
2. 解决启动时读取配置为null的问题
ASP.NET Core使用WebApplication.CreateBuilder(args)时,默认已包含环境变量(含Azure应用设置)作为配置源,无需额外调用builder.Configuration.AddEnvironmentVariables();。启动时读取为null的核心原因是Azure槽位配置注入时机滞后:应用启动初期,槽位环境变量尚未完全注入到进程中,而请求处理阶段环境变量已加载完成,因此此时能读取到值。
方法A:延迟读取(推荐)
将启动时需要使用的配置,改为通过依赖注入获取,避免在启动阶段同步读取。以Swagger标题为例:
builder.Services.AddSwaggerGen(c => { // 使用延迟委托,在Swagger生成时才读取配置 c.SwaggerDoc("v1", new OpenApiInfo { Title = () => builder.Configuration["VariableName"], Version = "v1" }); });
更规范的方式是使用IOptions模式绑定配置:
- 定义配置类:
public class ApiSettings { public string VariableName { get; set; } }
- 在
Program.cs中绑定配置:
builder.Services.Configure<ApiSettings>(builder.Configuration);
- 在需要使用的服务/控制器中注入
IOptions<ApiSettings>:
public class SomeService { private readonly ApiSettings _settings; public SomeService(IOptions<ApiSettings> settings) { _settings = settings.Value; // 此处可正常获取_settings.VariableName } }
方法B:强制重新加载配置
在启动时显式触发配置源重新加载,确保Azure环境变量已被加载:
// 在读取配置前调用 await builder.Configuration.ReloadAsync(); builder.Services.AddSwaggerGen(c => { string title = builder.Configuration["VariableName"]; c.SwaggerDoc("v1", new OpenApiInfo { Title = title, Version = "v1" }); });
3. 验证配置加载顺序
ASP.NET Core默认配置加载优先级从低到高为:
- 内存配置
appsettings.jsonappsettings.{Environment}.json- 用户机密(开发环境)
- 环境变量
- 命令行参数
Azure应用设置以环境变量形式注入,优先级高于本地配置文件。可添加调试代码确认配置源:
foreach (var source in builder.Configuration.Sources) { Console.WriteLine($"配置源类型:{source.GetType().Name}"); }
内容的提问来源于stack exchange,提问作者AaronC

