用于 DBContext 的 Azure KeyVault:"No database provider has been configured for this DbContext"

Azure KeyVault for DBContext: "No database provider has been configured for this DbContext"

我正在使用 .NET Core 2.1 构建 Web API。这将作为 Azure Web 应用程序托管。我想将我的数据库连接字符串保存在我的 Azure Key Vault 中。这是我在 Startup.cs ConfigureServices 方法中输入的代码:

services.AddDbContext<dbContext>(async options => 
        {
            var keyVaultUri = new Uri("https://xxxxxxxxx.vault.azure.net/");
            var azureServiceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
            SecretBundle connectionStringSecret = await keyVaultClient.GetSecretAsync(keyVaultUri + "secrets/DBConnectionString");
            options.UseSqlServer(connectionStringSecret.Value);
        });

当我尝试向注入了 dbContext 的控制器发出 HTTP Get 时,出现以下错误:

InvalidOperationException: No database provider has been configured 
for this DbContext. A provider can be configured by overriding the
DbContext.OnConfiguring method or by using AddDbContext on the 
application service provider. If AddDbContext is used, then also 
ensure that your DbContext type accepts a DbContextOptions<TContext> 
object in its constructor and passes it to the base constructor for 
DbContext.

我假设这是因为我使用异步 lambda 从 Key Vault 获取连接字符串,但是,我不确定该怎么做。这是从 Azure KeyVault 获取连接字符串以用于 Startup.cs 的正确方法吗?我应该以不同的方式做到这一点吗?任何帮助,将不胜感激。谢谢

您的配置失败的原因是回调现在是 async void。 从 lambda 上看这并不明显,但它实际上是即发即忘。 当您等待 Key Vault 客户端时,它 returns 来自回调而不配置提供者。

至于解决方案,我认为最好将密钥保管库机密添加到配置系统中,这样您就可以从那里使用它们,就好像它们来自 JSON 文件或任何其他来源一样。

前段时间我写了一篇关于这个的文章:https://joonasw.net/view/aspnet-core-azure-keyvault-msi。 我在文章中使用托管身份进行身份验证,但我看到您也在使用它:)

这是一个示例,说明如何将 Key Vault 配置为 ASP.NET Core 2.x 中的配置源:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((ctx, builder) =>
        {
            //Build the config from sources we have
            var config = builder.Build();
            //Add Key Vault to configuration pipeline
            builder.AddAzureKeyVault(config["KeyVault:BaseUrl"]);
        })
        .Build();

我在文章中的示例实际上有点过于冗长,因为它将在内部使用 AzureServiceTokenProvider 来获取令牌。

您需要 Microsoft.Extensions.Configuration.AzureKeyVault 来获取 Key Vault 的配置提供程序。

Key Vault 中的秘密命名很重要。 例如,我们将覆盖以下连接字符串:

{
  "ConnectionStrings": {
    "DefaultConnection": "..."
  }
}

您必须创建一个名为 ConnectionStrings--DefaultConnection 的机密,并将连接字符串作为值。

然后在配置时您只需使用 Configuration["ConnectionStrings:DefaultConnection"] 来获取连接字符串。 如果添加了 Key Vault 配置并找到了具有正确名称的机密,它将来自 Key Vault。