ASP.NET Core 2 + Получить экземпляр db-контекста
Я пытаюсь получить экземпляр DbContext (так что я могу сделать некоторые дополнительные работы при запуске с ним), я получаю следующую ошибку при попытке получить экземпляр в методе Configure:
System.InvalidOperationException: "Не удается разрешить ограниченную службу" MyApp.Data.MyDbContext "от корневого провайдера.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("MyDbContext")));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var dbContext = app.ApplicationServices.GetService(typeof(MyDbContext)) as MyDbContext;
}
Я могу получить доступ к экземпляру штрафа DbContext через контроллер и т.д.
Ответы
Ответ 1
Комментарий Пол Хейлса верен, но этот метод лучше работает в .NET Core 1.0.
В ASP.NET Core 2.0, как правило, плохая идея запускать любую настройку базы данных в Startup.cs
. Это связано с тем, что если вы выполните какие-либо миграции из CLI или Visual Studio, он запустит все Startup.cs
и попытается запустить вашу конфигурацию, которая завершится с ошибкой. Конечно, если вы не используете Entity-Framework, то это не проблема, однако ее еще не рекомендуется использовать в версии 2.0. Теперь рекомендуется сделать это в Program.cs
.
Например, вы можете создать метод расширения IWebHost
, который будет запускать любую необходимую настройку.
public static IWebHost MigrateDatabase(this IWebHost webHost)
{
var serviceScopeFactory = (IServiceScopeFactory)webHost.Services.GetService(typeof(IServiceScopeFactory));
using (var scope = serviceScopeFactory.CreateScope())
{
var services = scope.ServiceProvider;
var dbContext = services.GetRequiredService<YourDbContext>();
dbContext.Database.Migrate();
}
return webHost;
}
И затем в Program.cs
вы можете вызвать этот метод перед запуском.
public static void Main(string[] args)
{
BuildWebHost(args)
.MigrateDatabase()
.Run();
}
Ответ 2
Просто чтобы добавить к превосходному ответу @Travis, предпочтительный синтаксис метода Main
немного изменился по сравнению с Core 2.1 и теперь Main
метод по умолчанию теперь имеет CreateWebHostBuilder
вместо BuildWebHost
.
Пересмотренный код для вызова метода расширения показан ниже.
NB: здесь важен порядок, метод Build
возвращает WebHost
, который расширяет метод расширения, поэтому вам нужно вызвать метод migrate после Build()
и перед Run()
):
public static void Main(string[] args)
{
CreateWebHostBuilder(args)
.Build()
.MigrateDatabase()
.Run();
}
В нашем проекте более одного DbContext
, поэтому я изменил метод расширения на универсальный метод, который может принимать любой тип DbContext
:
public static IWebHost MigrateDatabase<T>(this IWebHost webHost) where T:DbContext
{
var serviceScopeFactory = (IServiceScopeFactory)webHost
.Services.GetService(typeof(IServiceScopeFactory));
using (var scope = serviceScopeFactory.CreateScope())
{
var services = scope.ServiceProvider;
var dbContext = services.GetRequiredService<T>();
dbContext.Database.Migrate();
}
return webHost;
}
Затем вы можете объединить вызовы для переноса различных контекстов:
CreateWebHostBuilder(args)
.Build()
.MigrateDatabase<ApiAuthDbContext>()
.MigrateDatabase<MainDbContext>()
.MigrateDatabase<SomeOtherDbContext>()
.Run();