ConfigurationManager возвращает null при использовании для извлечения строки подключения к базе данных при добавлении миграции

#c# #configuration #.net-core #entity-framework-core-2.2

#c# #конфигурация #.net-core #entity-framework-core-2.2

Вопрос:

Я использую Entity Framework Core в своем консольном приложении .NET Core. Я сохраняю свою строку подключения в App.config файле и использую ConfigurationManager в классе контекста для доступа к строке подключения.

Когда я хочу добавить новую миграцию в свой проект, я получаю следующую ошибку:

System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта.

в EF_tut.Context.OnConfiguring(DbContextOptionsBuilder optionsBuilder) в C:..Context.cs:line 12
в Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
в Microsoft.EntityFrameworkCore.Внутренний.InternalAccessorExtensions.GetService[TService] ( 1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func
фабрика IInfrastructure 1) в Microsoft.EntityFrameworkCore.Design.Внутренний.DbContextOperations.createContext(String ContextType) в Microsoft.EntityFrameworkCore.Design.Внутренний.MigrationsOperations.AddMigration(строковое имя, строковый outputDir, строковый ContextType) в Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(строковое имя, строковый outputDir, строковый ContextType) в Microsoft.EntityFrameworkCore.Design.OperationExecutor.Операционная база.<>c__DisplayClass3_0`1.b__0() в Microsoft.EntityFrameworkCore.Design.OperationExecutor.Операционная база.Выполнить (действие действия)

Ссылка на объект не установлена для экземпляра объекта.

Это мой App.config файл:

 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
         <add name="EfTutDb" 
              connectionString="Data Source=.;Initial Catalog=EF_tut;Integrated Security=True;"/>
    </connectionStrings>
</configuration>
  

и это мой класс контекста:

 class Context : DbContext
{
    public DbSet<Student> Students { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["EfTutDb"].ConnectionString); // Line 12.
    }
}
  

Когда я пытаюсь получить строку подключения, используя ConfigurationManger метод main, я получаю строку подключения, но когда я добавляю миграцию, я получаю ошибку ссылки Null.

Комментарии:

1. .Net core имеет другую систему конфигурации. Я не знаю, работает ли ConfigurationManager, но даже если это так, я предлагаю вам не использовать его.

2. сегодня я столкнулся с той же проблемой, я пытаюсь разделить классы домена, поэтому мне это нужно в отдельной библиотеке для подключения к azure sql и использования app.config для connectionstring . Использование ConfigurationManager. ConnectionStrings[«AzureTestDbContext»] . ConnectionString возвращает ‘System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта.’. есть ли возможность использовать ConfigurationManager? мое временное решение также использовало жестко закодированную строку подключения.

Ответ №1:

Ядро EF создает экземпляр контекста БД во время разработки, например, Add-migration или Update-Database, для сбора сведений об объектах и их сопоставления.

https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/#design-time-dbcontext-configuration

Но App.config вашего проекта недоступен с помощью ConfigurationManager, поскольку EF core design-time — это другое приложение со своими собственными настройками приложения.

Я столкнулся с той же проблемой и нашел это решение, которое работает для меня:

App.config:

 <configuration>
<connectionStrings>
    <add name="Default" 
        connectionString="Data Source=(LocalDb)MSSQLLocalDB;Initial Catalog=EFCoreSample;Integrated Security=SSPI"/>
</connectionStrings>
  

Добавьте конструктор в контекст БД, который получает DbContextOptions и передает его базовому конструктору:

 public class EFCoreSampleDbContext : DbContext
{
    public EFCoreSampleDbContext(DbContextOptions options)
        : base(options)
    {

    }
}
  

Определите фабрику контекста DB во время разработки, которая использует ConfigurationBuilder для извлечения строки подключения из App.config. Когда вы выполняете команду, такую как add-migration, ядро EF ищет класс внутри проекта, который реализует IDesignTimeDbContextFactory для получения экземпляра контекста БД, и если не найден, создает экземпляр контекста БД самостоятельно.

Вы можете найти больше о фабрике контекста DB во время разработки здесь:

https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-a-design-time-factory[2]

Вам необходимо добавить пакеты Nuget Microsoft.Расширения.Конфигурация, Microsoft.Расширения.Конфигурация.Расширения файлов и Microsoft.Расширения.Конфигурация.Xml для этого. Кроме того, установите для свойства «Копировать в выходной каталог» файла App.config значение «Копировать всегда».

 public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<EFCoreSampleDbContext>
{
    public EFCoreSampleDbContext CreateDbContext(string[] args)
    {
        var optionsBuilder =
            new DbContextOptionsBuilder<EFCoreSampleDbContext>();

        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddXmlFile("App.config")
            .Build();

        string connectionString;
        if (configuration
            .Providers
            .FirstOrDefault()
            .TryGet("connectionStrings:add:Default:connectionString",
                out connectionString))
        {

            optionsBuilder.UseSqlServer(connectionString);
            var dbContext =
                new EFCoreSampleDbContext(optionsBuilder.Options);
            return dbContext;
        }
        else
            throw new Exception("The design-time connection string not found!");
    }
}
  

Ответ №2:

Возможно, это немного обходной путь.. но это будет работать:

     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddXmlFile("App.config")
            .Build(); 

        optionsBuilder.UseSqlServer(configuration.GetValue<string>("connectionStrings:add:EfTutDb:connectionString"));
    }
}
  

Ответ №3:

Я не совсем уверен, но я думаю, что вы должны исправить строку подключения. Попробуйте это в своем классе:

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer("Server=YourPcName\YourSqlServerName;Database=YourDbName;Trusted_Connection=True;MultipleActiveResultSets=True;");
        }
    }
  

Комментарии:

1. Это работает, когда я жестко закодировал строку подключения в классе DbContext. Проблема заключается в использовании его через ConfigurationManager.

2. По правде говоря, я никогда не использовал Entity Framework в консольном приложении, только в Интернете. Разница между EF и EF-Core заключается в том, что EF-Core считывает строку подключения из файла json с именем appsettings.json, а не из Web.Config . Я думаю, что лучше всего было бы ознакомиться с официальной документацией и руководством здесь: entityframeworktutorial.net/efcore/… Удачи 🙂