Как получить настройки приложения из корня проекта в реализацию IDesignTimeDbContextFactory в ASP.NET Core 2.0 и EF Core 2.0

Я создаю приложение в ASP.NET Core 2.0, и у меня возникают проблемы с миграцией EntityFramework.

У меня DbContext находится в отдельном проекте (SolutionName \ ProjectNamePrefix .Data), поэтому я создал реализацию для интерфейса IDesignTimeDbContextFactory.

Я хотел использовать разные строки подключения для разных сред, и для этого мне нужен appsettings.json.

Итак, после быстрого поиска я обнаружил, что могу создать новый объект IConfigurationRoot внутри функции CreateDbContext, как показано здесь: https://codingblast.com/entityframework-core-idesigntimedbcontextfactory/

Я добавил это, а затем для тестирования попытался запустить dotnet ef migrations list -c MyContext из корневой папки проекта данных.

Затем я получил следующую ошибку:

The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\dev\*SolutionName*\*ProjectNamePrefix*.Data\bin\Debug\netcoreapp2.0\appsettings.json'.

Итак, в основном я попробовал 3 варианта получения правильного корневого пути:

  • Directory.GetCurrentDirectory();
  • env.ContentRootPath; (IHostingEnvironment объект, я нашел способ получить его здесь: https://github.com/aspnet/Home/issues/2194)
  • AppDomain.CurrentDomain.BaseDirectory;

и все они вернули один и тот же путь ..\bin\debug\netcoreapp2.0\. Когда я запускаю проект Data из VS, два первых варианта дают мне правильную корневую папку проекта.

Есть ли способ получить правильную корневую папку с содержимым проекта?

Потому что, когда я добавил --verbose к команде EF, она вышла из системы:

Using content root 'C:\dev\FitsMeIdentity\FitsMeIdentity.Data\'.

Итак, я понимаю, что EF каким-то образом знает корень проекта, но все параметры, упомянутые выше, возвращают путь для уже созданного приложения.

Единственный работающий вариант, который я нашел, - это то, что я меняю Copy output to root folder на Copy always, но нашел здесь: https://www.benday.com/2017/02/17/ef-core-migrations-without-hard-coding-a-connection-string-using-idbcontextfactory/, что это плохая идея.

Сначала я даже подумал о создании конструктора для реализации IDesignTimeDbContextFactory, который получает IOptions в качестве параметра, но это не сработало, возникла та же проблема, что и здесь: Внедрение строки Env Conn в .NET Core 2.0 с EF Core DbContext в разных class lib, чем Startup prj, и реализация IDesignTimeDbContextFactory


person V. Samma    schedule 01.11.2017    source источник


Ответы (2)


Нет. Вы не можете этого сделать, и что более важно: вы не должны этого делать. Вся суть IDesignTimeDbContextFactory в том, что это способ получить DbContext экземпляр в контексте, где нет платформы ASP.NET Core для работы, то есть из библиотеки классов. Если вы выполняете миграцию из проекта ASP.NET Core, он вам не нужен, а если нет, то никакая конфигурация недоступна.

Кроме того, его следует использовать только для разработки, отсюда и часть названия "DesignTime". В результате отпадает необходимость в таких вещах, как переключение между строками подключения для разных сред. Просто жестко запрограммируйте строку подключения как docs подробнее.

person Chris Pratt    schedule 01.11.2017
comment
Спасибо за быстрый ответ. Ладно, может, тогда я что-то упускаю из общей картины. Каков предполагаемый способ применения миграции EF к промежуточной / производственной средам? Я не должен использовать Update-Database, но должен ли я использовать Script-Migration, чтобы получать сценарии SQL и запускать их каждый раз вручную? - person V. Samma; 01.11.2017
comment
Ага. Этот или какой-либо другой метод создания версионных миграций, например ReadyRoll или аналогичные продукты. Вместо этого вы также можете создать проект базы данных. Короче говоря, есть много разных способов внести изменения в базу данных в производство. Просто найдите то, что вам подходит. - person Chris Pratt; 01.11.2017
comment
Я смущен. Я думал, что Entity Framework - это инструмент для сквозного управления базами данных. Цитата this: What's the point of this easy to use system if you can't take it all the way? Мне не имеет смысла использовать сторонний инструмент для развертывания производственной БД. Или хотя бы не платные инструменты. И на веб-сайте ReadyRoll прямо сказано, что: Please note that ReadyRoll's integration with Entity Framework CodeFirst is evolving and may not be suitable for production use. Я тем временем изучу DbUp, но, похоже, это добавит сложности. - person V. Samma; 02.11.2017
comment
Entity Framework - это просто ORM. Это не является и никогда не утверждалось, что это комплексное решение для всего, что вам когда-либо понадобится для работы с базой данных. Развертывание производства - это процесс. Должны быть политики управления изменениями, и в большинстве корпоративных ситуаций вы никогда не сможете получить миграцию EF на расстоянии вытянутой руки от производственной базы данных. - person Chris Pratt; 02.11.2017
comment
Таким образом вы можете получить доступ к appsettings.json конфигурации в своей IDesignTimeDbContextFactory реализации - см. Мой ответ на Внедрение строки Env Conn в .NET Core 2.0 с EF Core DbContext в другом классе lib, чем Startup prj, и реализация IDesignTimeDbContextFactory - person Dmitry Pavlov; 26.12.2018

Немного поздно, но вот решение для тех, кто ненавидит жестко запрограммированные строки соединений:

internal class MigrationDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
    public AppDbContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", false)
            .Build();
        
        string connectionString = configuration.GetConnectionString("DefaultConnection");

        DbContextOptionsBuilder<AppDbContext> optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
        optionsBuilder.UseMySql(connectionString,
            ServerVersion.AutoDetect(connectionString),
            mySqlOptions =>
                mySqlOptions.EnableRetryOnFailure(
                    maxRetryCount: 10,
                    maxRetryDelay: TimeSpan.FromSeconds(30),
                    errorNumbersToAdd: null));

        return new AppDbContext(optionsBuilder.Options);
    }
}
person Sean Thorburn    schedule 20.02.2021