114

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);
}
5
  • Don't know about the latest version, but in the earlier version you still had to add the .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) to your ConfigurationBuilder. Have you done this? Are 'normal' Application Settings working?
    – Jan_V
    Commented Aug 21, 2017 at 12:19
  • 1
    In Core2.0 this is done automatically: andrewlock.net/…
    – borisdj
    Commented Aug 21, 2017 at 12:23
  • In Core2.0 you can use System.AppContext.BaseDirectory to get the base path, in case you can't do it in the startup as mention @borisdj: github.com/aspnet/Announcements/issues/237 Commented Nov 30, 2017 at 22:21
  • 3
    For those wondering where SetBasePath comes from: stackoverflow.com/questions/46843367/… and where AddJsonFile comes from: stackoverflow.com/questions/27382481/… Commented Jan 15, 2018 at 12:39
  • Thank you! I think you should post a separate answer with your solution instead of embedding it in your question. Commented May 29, 2019 at 6:09

14 Answers 14

162

STEP 1: Include the following in OnConfiguring()

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json")
            .Build();
        optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
    }

STEP 2: Create appsettings.json:

  {
    "ConnectionStrings": {       
      "DefaultConnection": "Server=YOURSERVERNAME; Database=YOURDATABASENAME; Trusted_Connection=True; MultipleActiveResultSets=true"        
    } 
  }

STEP 3: Hard copy appsettings.json to the correct directory

  Hard copy appsettings.json.config to the directory specified in the AppDomain.CurrentDomain.BaseDirectory directory. 
  Use your debugger to find out which directory that is.        

Assumption: you have already included package Microsoft.Extensions.Configuration.Json (get it from Nuget) in your project.

8
  • 8
    I would disagree! "Copy appsettings.json" with the connection string inside is as bad as stating the connection string in 2 places! Who will be in charge to keep it insync?
    – Marcel
    Commented Sep 14, 2017 at 12:42
  • 3
    The background of the question where both myself and borisdj ran into, is that in .NET Core 2.0 System.Configuration is not there anymore and need to be replaced. To make the answer as easy to follow by others I choose in Step 3 for the hard copy approach. But you are of course correct that in a real world scenario you will add "appsetting.json" to your project and set the "Copy to Output Directory" in the "General-Advanced" tab in the "Property Pages" to "Copy Always", after which manual copy actions should not be necessary anymore.
    – JRB
    Commented Sep 14, 2017 at 13:17
  • 2
    If you'd like to get connection strings from custom section of your appsettings.json check this stackoverflow.com/a/53924899/804385 Commented Dec 25, 2018 at 19:00
  • 1
    Where do I find OnConfiguring ?
    – MC9000
    Commented Mar 1, 2019 at 3:56
  • 1
    @MC9000 in your DbContext file next to OnModelCreating Commented May 9, 2019 at 16:17
24

In ASPNET Core you do it in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
}

where your connection is defined in appsettings.json

{
  "ConnectionStrings": {
    "BloggingDatabase": "..."
  },
}

Example from MS docs

2
  • can you please check this stackoverflow.com/questions/57000395/… I was not able to configure the connectionString in appsettings.json
    – Gopi
    Commented Jul 12, 2019 at 5:18
  • 3
    What if I want to use the DbContext in a different project, for example when having a separate project for the DA-layer?
    – Chris
    Commented Jun 16, 2021 at 15:19
16

There are a couple things missing, both from the solutions above and also from the Microsoft documentation. If you follow the link to the GitHub repository linked from the documentation above, you'll find the real solution.

I think the confusion lies with the fact that the default templates that many people are using do not contain the default constructor for Startup, so people don't necessarily know where the injected Configuration is coming from.

So, in Startup.cs, add:

 public IConfiguration Configuration { get; }
 public Startup(IConfiguration configuration) 
 {
     Configuration = configuration;
 }

and then in ConfigureServices method add what other people have said...

services.AddDbContext<ChromeContext>(options =>                    
    options.UseSqlServer(Configuration.GetConnectionString("DatabaseConnection")));

you also have to ensure that you've got your appsettings.json file created and have a connection strings section similar to this

{
  "ConnectionStrings": {
    "DatabaseConnection": "Server=MyServer;Database=MyDatabase;Persist Security Info=True;User ID=SA;Password=PASSWORD;MultipleActiveResultSets=True;"
  }
}

Of course, you will have to edit that to reflect your configuration.

Things to keep in mind. This was tested using Entity Framework Core 3 in a .Net Standard 2.1 project. I needed to add the nuget packages for: Microsoft.EntityFrameworkCore 3.0.0 Microsoft.EntityFrameworkCore.SqlServer 3.0.0 because that's what I'm using, and that's what is required to get access to the UseSqlServer.

5
  • This is great, thank you so much! I have been looking for this for hours now.
    – dazoar
    Commented Mar 17, 2020 at 11:43
  • what is ChromeContext ? Commented Jun 23, 2021 at 11:25
  • I am getting error , using (var context = new pixelleContext()) { return context.Specsheet.ToList(); } Commented Jun 23, 2021 at 11:26
  • 1
    @rahularyansharma Maybe start your own question and put a link to this one? That way you can be a bit more thorough with your code sample? In context, your code snippet above is not very helpful. In my sample, ChromeContext is the name of the database context
    – Kevon
    Commented Jun 24, 2021 at 19:41
  • its solved for now : stackoverflow.com/questions/68099089/… Commented Jun 25, 2021 at 7:02
12

I understand this has been marked as answered but I ran into a bit of a problem when I was working on a project where I have my EF Core Data Access Layer in a .DLL Project separated from the rest of my project, API, Auth and Web and mostly will like my other projects to reference this Data project. And I don't want to want to come into the Data project to change connection strings everytime.

STEP 1: Include this in the OnConfiguring Method

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
           var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
           IConfigurationRoot configuration = new ConfigurationBuilder()
                **.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))**
                .AddJsonFile("appsettings.json", optional: false)
                .AddJsonFile($"appsettings.{envName}.json", optional: false)
                .Build();
           optionsBuilder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
      }

NOTE: .SetBasePath(Path.Combine(Directory.GetCurrentDirectory())) This will negate or invalidate the need to copy the file to a directory as ASP.NET CORE is smart enough to pick the the right file. Also the environment specified will pick right file when the building for Release or Production, assuming the Prod environment file is selected.

STEP 2: Create appsettings.json

{
"ConnectionStrings": {       
  "DefaultConnection": "Server=YOURSERVERNAME; Database=YOURDATABASENAME; Trusted_Connection=True; MultipleActiveResultSets=true"        
} 

}

PLEASE: Referece: Microsoft.Extensions.Configuration

2
  • I am in the same situation as you and I tried this. However, ConfigurationBuilder does not have a method "SetBasePath". I suspect it's because I am using Standard for my DLL as opposed to Core.
    – EGP
    Commented May 14, 2020 at 14:29
  • 1
    Try Microsoft.Extensions.Configurations.Json Package. Commented Nov 10, 2022 at 7:12
6

If you are using "top level statements", you can get your connection string as follows:

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
5

How about passing it as dp injection into that class? in ConfigureServices:

services.Configure<MyOptions>(Configuration);

create class to hold json strings:

public class MyOptions
{
    public MyOptions()
    {

    }
    public string Option1 { get; set; }
    public string Option2 { get; set; }
}    

Add strings to json file:

"option1": "somestring",
"option2": "someothersecretstring"

In classes that need these strings, pass in as constructor:

public class SomeClass
{
 private readonly MyOptions _options;

    public SomeClass(IOptions<MyOptions> options)
    {
        _options = options.Value;           
    }    

 public void UseStrings()
 {
   var option1 = _options.Option1;
    var option2 = _options.Option2;
 //code
 }
}
5
  • 1
    I don"t see how this solves the problem. Can you edit the answer and integrate your solution into the example from question.
    – borisdj
    Commented Aug 24, 2017 at 9:02
  • 1
    @borisdj How can you not see that it offers a solution to the OP's problem? Commented Sep 6, 2017 at 16:44
  • 1
    @JohanHerstad I have tried your solution, a good idea but I think because IDesignTimeDbContextFactory<AppContext> is called at design time and not runtime you cannot inject IOptions into contructors, you see my question here that explains further: stackoverflow.com/questions/46085500/… Commented Sep 6, 2017 at 23:01
  • 1
    The code that does the creation of the IDesignTimeDbContextFactory in Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations uses Activator, so it requires a parameterless constructor.
    – Erikest
    Commented Feb 1, 2018 at 0:57
  • Yes, of course. I knew I've been exposed to it but I just couldn't understand that at the time and didn't have the time to really research it. I just know I had to also implement it at some time in the future, never forgot this problem. I love that you have taken the time to give an answer below so long after the first question was asked. Commented Feb 2, 2018 at 7:20
4

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 to WebHost.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 any IDesignTimeDbContextFactory 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 a DbContextOptions (which happens in your Startup.ConfigureServices when you use AddDbContext or AddDbContextPool) and adds those factories. Finally, it looks through the assembly for any DbContext derived classes and creates a factory method that just calls Activator.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 need IDesignTimeDbContextFactory.

1
  • 2
    It won't work if I have DbContext in a separate project.
    – Konrad
    Commented Jun 6, 2018 at 10:25
4
        var builder = WebApplication.CreateBuilder();
        string conStr = builder.Configuration.GetConnectionString("myDb1");
        SqlConnection conn = new SqlConnection(conStr);
1

You can also do this in ASP.NET Core 2 by defining the connection string in your appSettings.json file. Then in your Startup.cs you specify which connection string to use.

appSettings.json

{
    "connectionStrings": {
        "YourDBConnectionString": "Server=(localdb)\\mssqllocaldb;Database=YourDB;Trusted_Connection=True"
    }
}

Startup.cs

public static IConfiguration Configuration { get; private set;}

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}
var connectionString = Configuration["connectionStrings:YourDBConnectionString"];
services.AddDbContext<YourDbContext>(x => x.UseSqlServer(connectionString));
1

just use

string connectionString =
     builder.Configuration.GetConnectionString("TestDBConnectionString");
0
  1. Add the following code into startup.cs file.

    public void ConfigureServices(IServiceCollection services)
    {
        string con = Configuration.GetConnectionString("DBConnection");
        services.AddMvc();
        GlobalProperties.DBConnection = con;//DBConnection is a user defined static property of GlobalProperties class
    }
    
  2. Use GlobalProperties.DBConnection property in Context class.

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {  
              optionsBuilder.UseSqlServer(GlobalProperties.DBConnection);
        }
    }
    
0
0

It's not fancy I known but you could use a callback class, create a hostbuilder and set the configuration to a static property.

For asp core 2.2:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using System;

namespace Project
{
    sealed class Program
    {
        #region Variables
        /// <summary>
        /// Last loaded configuration
        /// </summary>
        private static IConfiguration _Configuration;
        #endregion

        #region Properties
        /// <summary>
        /// Default application configuration
        /// </summary>
        internal static IConfiguration Configuration
        {
            get
            {
                // None configuration yet?
                if (Program._Configuration == null)
                {
                    // Create the builder using a callback class
                    IWebHostBuilder builder = WebHost.CreateDefaultBuilder().UseStartup<CallBackConfiguration>();

                    // Build everything but do not initialize it
                    builder.Build();
                }

                // Current configuration
                return Program._Configuration;
            }

            // Update configuration
            set => Program._Configuration = value;
        }
        #endregion

        #region Public
        /// <summary>
        /// Start the webapp
        /// </summary>
        public static void Main(string[] args)
        {
            // Create the builder using the default Startup class
            IWebHostBuilder builder = WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();

            // Build everything and run it
            using (IWebHost host = builder.Build())
                host.Run();
        }
        #endregion


        #region CallBackConfiguration
        /// <summary>
        /// Aux class to callback configuration
        /// </summary>
        private class CallBackConfiguration
        {
            /// <summary>
            /// Callback with configuration
            /// </summary>
            public CallBackConfiguration(IConfiguration configuration)
            {
                // Update the last configuration
                Program.Configuration = configuration;
            }

            /// <summary>
            /// Do nothing, just for compatibility
            /// </summary>
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                //
            }
        }
        #endregion
    }
}

So now on you just use the static Program.Configuration at any other class you need it.

0

If you need in different Layer :

Create a Static Class and expose all config properties on that layer as below :

using Microsoft.Extensions.Configuration;
using System.IO;

namespace Core.DAL
{
    public static class ConfigSettings
    {
        public static string conStr1 { get ; }
        static ConfigSettings()
        {
            var configurationBuilder = new ConfigurationBuilder();
            string path = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
            configurationBuilder.AddJsonFile(path, false);
            conStr1 = configurationBuilder.Build().GetSection("ConnectionStrings:ConStr1").Value;
        }
    }
}

-1

Extension:

using Microsoft.Extensions.Configuration;
using System.Collections.Generic;

public static class MyExtensions
{
  public static IDictionary<string, string> GetAllConnectionStrings(this IConfiguration obj)
  {
     var dic = new Dictionary<string, string>();
     var section = obj.GetSection("ConnectionStrings").GetChildren();
     foreach (var cnn in section)
     {
        dic.Add(cnn.Key, cnn.Value);
     }
     return dic;
  }
}

Use:

var cnns = builder.Configuration.GetAllConnectionStrings();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.