在 Azure Key Vault 配置 ASP.NET Core 3.1 之后,在 Debug 中启动我的网站无法正常工作

Starting my website in Debug not working after Azure Key Vault Configuration ASP.NET Core 3.1

我有一个功能齐全的网站。昨天我使用 Azure Key Vault 服务绑定了我的秘密。 在我的秘密中,我只存储了 SendGridKey 和 EmailKey。 我的 csproj 文件中添加了以下依赖项:

<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.0.2" />
<PackageReference Include="Azure.Identity" Version="1.3.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.1.0" />

我的Program.cs文件已经自动更新如下:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
                {
                    var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable("MyKeyVault"));
                    config.AddAzureKeyVault(
                    keyVaultEndpoint,
                    new DefaultAzureCredential());
                })
            .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();

                });

在 Azure 中发布网站仍然可以完美运行,但我无法以调试方式启动我的网站。

我收到以下错误:

An error occurred while starting the application.
ArgumentNullException: Value cannot be null. (Parameter 'uriString')
System.Uri..ctor(string uriString)
ArgumentNullException: Value cannot be null. (Parameter 'uriString')

问题是:

var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable("MyKeyVault"));

因为 Environment.GetEnvironmentVariable("MyKeyVault") 返回 NULL

我的启动文件是:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        var options = new RewriteOptions()
            .AddRedirectToWwwPermanent()
            .AddRedirectToHttpsPermanent();

        app.UseRewriter(options);

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

有什么建议吗?

更新

我有一个类似的项目,代码块如下:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                var keyVaultEndpoint = GetKeyVaultEndpoint();
                if (!string.IsNullOrEmpty(keyVaultEndpoint))
                {
                    var azureServiceTokenProvider = new AzureServiceTokenProvider();
                    var keyVaultClient = new KeyVaultClient(
                        new KeyVaultClient.AuthenticationCallback(
                            azureServiceTokenProvider.KeyVaultTokenCallback));
                    config.AddAzureKeyVault(keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                }
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    private static string GetKeyVaultEndpoint() => "https://mykeyvault.vault.azure.net/";

我使用了以下软件包:

<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.0.0" />
<PackageReference Include="Azure.Identity" Version="1.1.1" />
<PackageReference Include="Microsoft.Azure.KeyVault.Core" Version="3.0.5" />
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="3.1.8" />
<PackageReference Include="SendGrid" Version="9.21.0" />

Microsoft.Azure.Services.AppAuthentication 已被弃用,上面的代码在我的新项目中不再有效。它确实适用于我的旧版本。

要调试环境变量问题,将应用程序可以看到的所有变量转储到控制台或日志中可能是一个有用的调试技巧。

使用如下代码:

    foreach(DictionaryEntry env in Environment.GetEnvironmentVariables())
    {
        Console.WriteLine(env.Key + ":" + env.Value);
    }

注意这样做的安全问题,因为秘密可能最终出现在错误的地方。另一种方法是只打印出变量名或每个变量的前几个字符,比如

Console.WriteLine(env.Key + " : " + env.Value.ToString().Substring(0,5));

通过这几行代码,它在开发和生产中再次起作用:

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
                {
                    if (context.HostingEnvironment.IsDevelopment())
                    {

                        // Do simply nothing
                    }
                    else
                    {
                        var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable("MyKeyVault"));
                        config.AddAzureKeyVault(
                        keyVaultEndpoint,
                        new DefaultAzureCredential());
                    }
                                           
                })
            .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

在开发中,机密从 secrets.json 中检索,在生产中从 Azure KeyVault 中检索。