I have an Entity Framework Core + ASP.NET Core application and when my application starts up I want to ensure that the database is created, and eventually (once I have migrations) I want to ensure that those are also run.
Initially I put Database.EnsureCreated()
into the constructor of my DbContext
but that appears to run every time someone hits my application since a new instance of the DbContext
is created each time.
I tried to put it into my startup code, but I need an instance of my DbContext
to do that and it is unclear how exactly to get one. I am configuring EF as so:
serviceCollection.AddEntityFramework()
.AddSqlServer()
.AddDbContext<Models.MyContext>(options => options.UseSqlServer(...));
I don't see a way to get an instance of the DbContext from the service collection, and I don't see any appropriate singleton to inject a DbContext into so I can do some one-time initialization.
So what is the best place to ensure some code related to my DbContext is called once per application run?
At the time of this writing, there is not a "correct" place to run code on application startup such that it executes within the request scope (see https://github.com/aspnet/Hosting/issues/373).
For now, the workaround is to do the following, but it won't work in more complex multi-application scenarios (see https://github.com/aspnet/EntityFramework/issues/3070#issuecomment-142752126)
public class Startup
{
...
public void Configure(IApplicationBuilder applicationBuilder, ...)
{
...
// NOTE: this must go at the end of Configure
var serviceScopeFactory = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
using (var serviceScope = serviceScopeFactory.CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<MyDbContext>();
dbContext.Database.EnsureCreated();
}
}
}