I have the following class in NET Core2.0 App.
// required when local database does not exist or was deleted
public class ToDoContextFactory : IDesignTimeDbContextFactory<AppContext>
{
public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseSqlServer("Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true");
return new AppContext(builder.Options);
}
}
This is required in Core 2.0 with migration when Database does not exist and has to be created when you run update-database.
Unable to create migrations after upgrading to ASP.NET Core 2.0
I would like not having ConnectionString in 2 places(here and in appsettings.json) but only in .json so I have tried to replace
"Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true"
with
ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString
but it's not working, I'm getting null value.
UPDATE 1:
Just to note that adding explicitly .json is not necessery in Core 2 so the problem is not with the file.
https://andrewlock.net/exploring-program-and-startup-in-asp-net-core-2-preview1-2/
UPDATE 2:
Also I am already using Configuration for sending ConnectionString from .json to Context:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}
But I can not use this for ToDoContextFactory because it does not have Configuration, and ToDoContextFactory is used by migrations so the App is not running at all.
SOLUTION: Based on answer from @JRB I made it work like this:
public AppContext CreateDbContext(string[] args)
{
string projectPath = AppDomain.CurrentDomain.BaseDirectory.Split(new String[] { @"bin\" }, StringSplitOptions.None)[0];
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(projectPath)
.AddJsonFile("appsettings.json")
.Build();
string connectionString = configuration.GetConnectionString("DefaultConnection");
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseSqlServer(connectionString);
return new AppContext(builder.Options);
}
There is actually a default pattern that you can employ to achieve this result without having to implement
IDesignTimeDbContextFactory
and do any config file copying.It is detailed in this doc, which also discusses the other ways in which the framework will attempt to instantiate your
DbContext
at design time.Specifically, you leverage a new hook, in this case a static method of the form
public static IWebHost BuildWebHost(string[] args)
. The documentation implies otherwise, but this method can live in whichever class houses your entry point (see src). Implementing this is part of the guidance in the 1.x to 2.x migration document and what's not completely obvious looking at the code is that the call toWebHost.CreateDefaultBuilder(args)
is, among other things, connecting your configuration in the default pattern that new projects start with. That's all you need to get the configuration to be used by the design time services like migrations.Here's more detail on what's going on deep down in there:
While adding a migration, when the framework attempts to create your
DbContext
, it first adds anyIDesignTimeDbContextFactory
implementations it finds to a collection of factory methods that can be used to create your context, then it gets your configured services via the static hook discussed earlier and looks for any context types registered with aDbContextOptions
(which happens in yourStartup.ConfigureServices
when you useAddDbContext
orAddDbContextPool
) and adds those factories. Finally, it looks through the assembly for anyDbContext
derived classes and creates a factory method that just callsActivator.CreateInstance
as a final hail mary.The order of precedence that the framework uses is the same as above. Thus, if you have
IDesignTimeDbContextFactory
implemented, it will override the hook mentioned above. For most common scenarios though, you won't needIDesignTimeDbContextFactory
.You can also do this in ASP.NET Core 2 by defining the connection string in your
appSettings.json
file. Then in yourStartup.cs
you specify which connection string to use.appSettings.json
Startup.cs
STEP 1: Include the following in OnConfiguring()
STEP 2: Create appsettings.json:
STEP 3: Hard copy appsettings.json to the correct directory
Assumption: you have already included package Microsoft.Extensions.Configuration.Json (get it from Nuget) in your project.
In ASPNET Core you do it in
Startup.cs
where your connection is defined in
appsettings.json
Example from MS docs
Add the following code into
startup.cs
file.Use
GlobalProperties.DBConnection
property inContext
class.How about passing it as dp injection into that class? in ConfigureServices:
create class to hold json strings:
Add strings to json file:
In classes that need these strings, pass in as constructor: