问题
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)
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)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(FuncObject 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