I have a ASP.NET MVC 6 application, and i need to call the Database.EnsureCreated and Database.Migrate methods.
But where should I call the
Ordinarily, the DbContext will be added to the dependency injection container in Startup.ConfigureServices() like so:
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)
{
// Add DbContext to the injection container
services.AddDbContext(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
}
However, the IServiceCollection doesn't act as a service provider, and since the DbContext was not registered with the injection container before the current scope (Startup.ConfigureServices), we can't access the context through dependency injection here.
Henk Mollema discusses manually resolving services during startup here, but mentions that...
manually resolving services (aka Service Locator) is generally considered an anti-pattern ... [and] you should avoid it as much as possible.
Henk also mentions that the Startup constructor's dependency injection is very limited and does not include services configured in Startup.ConfigureServices(), so DbContext usage is easiest and most appropriate through the injection container used throughout the rest of the app.
The runtime's hosting service provider can inject certain services into the constructor of the
Startupclass, such asIConfiguration,IWebHostEnvironment(IHostingEnvironmentin pre-3.0 versions),ILoggerFactoryandIServiceProvider. Note that the latter is an instance built by the hosting layer and contains only the essential services for starting up an application.
In order to call Database.EnsureCreated() or Database.Migrate(), we can, and want to, have the DbContext resolve automatically in Startup.Configure(), where our configured services are now available through DI:
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)
{
// Add DbContext to the injection container
services.AddDbContext(options =>
options.UseSqlServer(
this.Configuration.GetConnectionString("DefaultConnection")));
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyDbContext context)
{
if (env.IsDevelopment())
{
context.Database.EnsureCreated();
//context.Database.Migrate();
}
}
}
Please remember as Bassam Alugili's answer referenced from EF Core documentation that Database.EnsureCreated() and Database.Migrate() are not meant to be used together because one ensures your existing migrations are applied to the database, which is created if needed. The other just ensures a database exists, and if not, creates one that reflects your DbContext, including any seeding done through the Fluent API in the context.