ConfigurationManager return null when using to extract database connection string when add migration

风格不统一 提交于 2021-01-22 04:19:12

问题


I am using Entity Framework Core in my .NET Core console app. I store my connection string in the App.config file and use ConfigurationManager in context class to access the connection string.

When I want to add new migration to my project I get the following error:

System.NullReferenceException: Object reference not set to an instance of an object.

at EF_tut.Context.OnConfiguring(DbContextOptionsBuilder optionsBuilder) in C:\..\Context.cs:line 12
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
at Microsoft.EntityFrameworkCore.Internal.InternalAccessorExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func
1 factory) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType) at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Object reference not set to an instance of an object.

This is my App.config file:

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

and this is my context class:

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

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

When I try get connection string using ConfigurationManger in the main method, I get the connection string but when I add migration, I get Null Reference error.


回答1:


Maybe it's a bit workaround.. but this will work:

    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"));
    }
}



回答2:


The EF Core instantiates the DB context at design-times such as Add-migration or Update-Database, to gather details about the entities and map them.

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

But the App.config of your project is not accessible using the ConfigurationManager, since the EF core design-time is another application with its own application settings.

I faced the same problem and found this solution which works for me:

App.config:

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

Add a constructor to the DB context which receives a DbContextOptions and passes it to the base constructor:

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

    }
}

Define a design-time DB context factory, which uses ConfigurationBuilder to retrieve the connection string from the App.config. When you run a command such as add-migration, EF Core looks for a class inside the project which implements the IDesignTimeDbContextFactory to receive an instance of the DB context, and if not found, instantiates the Db context by itself.

You can find more about the design-time DB context factory here:

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

You need to add Nuget packages Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.FileExtensions, and Microsoft.Extensions.Configuration.Xml for this one. Also, set the "Copy to Output Directory" property of the App.config file to "Copy always".

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!");
    }
}



回答3:


I'm not quite certain, but I think you must fix the connection string. Try this in your class:

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


来源:https://stackoverflow.com/questions/55659207/configurationmanager-return-null-when-using-to-extract-database-connection-strin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!