Хотя тема документации называется Из служб приложений , она начинается с
Если ваш запускаемый проект является приложением ASP.NET Core, инструменты пытаются получить DbContextобъект от поставщика услуг приложения.
Похоже, они не ожидают, что типы проектов, кроме приложения ASP.NET Core, будут использовать поставщика услуг приложения:)
Затем он продолжается с
Инструменты сначала пытаются получить поставщика услуг, вызывая Program.BuildWebHost () и получая доступ к свойству IWebHost.Services.
и пример :
public static IWebHost BuildWebHost(string[] args) => ...
А вот прием, который работает с текущими (EF Core 2.1.3) битами.Инструменты на самом деле ищут в классе, содержащем вашу точку входа (обычно Program
), статический (не обязательно публичный) метод, называемый BuildWebHost
с параметрами string[] args
, и важную недокументированную часть - возврат тип не не должен быть IWebHost
!Это может быть любой объект, имеющий общедоступное свойство, например
public IServiceProvider Services { get; }
, что дает нам следующее решение:
class Program
{
// ...
// Helper method for both Main and BuildWebHost
static IServiceProvider BuildServiceProvider(string[] args)
{
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
return isc.BuildServiceProvider();
}
static void Main(string[] args)
{
BuildServiceProvider(args).GetService<TheApp>().Run();
}
// This "WebHost" will be used by EF Core design time tools :)
static object BuildWebHost(string[] args) =>
new { Services = BuildServiceProvider(args) };
}
Обновление: Начиная с версии v2.1, вы также можете использовать новый шаблон CreateWebHostBuilder
, но IMHO он просто добавляет еще один уровень сложности, который здесь не нужен (предыдущий шаблон все еще поддерживается).Это похоже, но теперь нам нужен метод с именем CreateWebHostBuilder
, который возвращает объект с открытым методом Build()
, возвращающий объект с открытым свойством Services
, возвращающим IServiceProvider
.Для повторного использования с Main
мы не можем использовать анонимный тип и должны создать 2 класса, что также делает его использование из Main
более подробным:
class AppServiceBuilder
{
public ServiceCollection Services { get; } = new ServiceCollection();
public AppServiceProvider Build() => new AppServiceProvider(Services.BuildServiceProvider());
}
class AppServiceProvider
{
public AppServiceProvider(IServiceProvider services) { Services = services; }
public IServiceProvider Services { get; }
}
class Program
{
// ...
static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Services.GetService<TheApp>().Run();
}
// This "WebHostBuilder" will be used by EF Core design time tools :)
static AppServiceBuilder CreateWebHostBuilder(string[] args)
{
var builder = new AppServiceBuilder();
ConfigureServices(builder.Services);
return builder;
}
}