I am using Azure KeyVault to get secrets in Program.cs:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.AddEnvironmentVariables();
var builtConfig = config.Build();
config.AddAzureKeyVault(
$"https://{builtConfig["KeyVault:Name"]}.vault.azure.net/",
builtConfig["KeyVault:ClientId"],
builtConfig["KeyVault:ClientSecret"]);
})
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
I have following code to seed data in Startup.cs inside of ConfigureServices so I could get Azure KeyVault values:
Task.Run(async () =>
{
try
{
var context = services.BuildServiceProvider().GetRequiredService<ApplicationDbContext>();
var userManager = services.BuildServiceProvider().GetRequiredService<UserManager<ApplicationUser>>();
await SeedData.Initialize(context, userManager, Configuration);
}
catch (Exception ex)
{
var logger = services.BuildServiceProvider().GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
});
Method:
public class SeedData
{
public static async Task Initialize(ApplicationDbContext context, UserManager<ApplicationUser> userManager, IConfiguration configuration)
{
// Look for any users.
if (context.Users.Any())
{
return; // DB has been seeded
}
var user = new ApplicationUser
{
Email = configuration["SeedData:InitialAdminUser"],
UserName = configuration["SeedData:InitialAdminUser"]
};
var password = configuration["SeedData:InitialAdminPassword"];
await userManager.CreateAsync(user, password);
await userManager.AddClaimAsync(user, new Claim(ClaimTypes.Role, "admin"));
}
}
To seed data it is recommended to use it in Program.cs instead of Startup. Why is that?
I had this in Program.cs but I couldn't get config values from AzureKeyVault, because AzureKeyVault is configured after(I can't get azure key vault secret values at this stage):
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
Task.Run(async () =>
{
// seeding initial admin user
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDbContext>();
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
var builder = services.GetRequiredService<IConfigurationRoot>();
await SeedData.Initialize(context, userManager, builder);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
});
host.Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.AddEnvironmentVariables();
var builtConfig = config.Build();
config.AddAzureKeyVault(
$"https://{builtConfig["KeyVault:Name"]}.vault.azure.net/",
builtConfig["KeyVault:ClientId"],
builtConfig["KeyVault:ClientSecret"]);
})
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
}
To achieve this in Program.cs I think one way is to move azurekeyvault to main before Task.Run?
What reckon you?