[c#] How to read connection string in .NET Core?

I want to read just a connection string from a configuration file and for this add a file with the name "appsettings.json" to my project and add this content on it:

{
"ConnectionStrings": {
  "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-

 WebApplica71d622;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
    "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
    "Default": "Debug",
    "System": "Information",
    "Microsoft": "Information"
   }
 }
}

On ASP.NET I used this:

 var temp=ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

Now how can I read "DefaultConnection" in C# and store it on a string variable in .NET Core?

This question is related to c# connection-string asp.net-core-1.0

The answer is


i have a data access library which works with both .net core and .net framework.

the trick was in .net core projects to keep the connection strings in a xml file named "app.config" (also for web projects), and mark it as 'copy to output directory',

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="conn1" connectionString="...." providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

ConfigurationManager.ConnectionStrings - will read the connection string.

    var conn1 = ConfigurationManager.ConnectionStrings["conn1"].ConnectionString;

The way that I found to resolve this was to use AddJsonFile in a builder at Startup (which allows it to find the configuration stored in the appsettings.json file) and then use that to set a private _config variable

public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        _config = builder.Build();
    }

And then I could set the configuration string as follows:

var connectionString = _config.GetConnectionString("DbContextSettings:ConnectionString"); 

This is on dotnet core 1.1


Too late, but after reading all helpful answers and comments, I ended up using Microsoft.Extensions.Configuration.Binder extension package and play a little around to get rid of hardcoded configuration keys.

My solution:

IConfigSection.cs

public interface IConfigSection
{
}

ConfigurationExtensions.cs

public static class ConfigurationExtensions
{
    public static TConfigSection GetConfigSection<TConfigSection>(this IConfiguration configuration) where TConfigSection : IConfigSection, new()
    {
        var instance = new TConfigSection();
        var typeName = typeof(TConfigSection).Name;
        configuration.GetSection(typeName).Bind(instance);

        return instance;
    }
}

appsettings.json

{
   "AppConfigSection": {
      "IsLocal": true
   },
   "ConnectionStringsConfigSection": {
      "ServerConnectionString":"Server=.;Database=MyDb;Trusted_Connection=True;",
      "LocalConnectionString":"Data Source=MyDb.db",
   },
}

To access a strongly typed config, you just need to create a class for that, which implements IConfigSection interface(Note: class names and field names should exactly match section in appsettings.json)

AppConfigSection.cs

public class AppConfigSection: IConfigSection
{
    public bool IsLocal { get; set; }
}

ConnectionStringsConfigSection.cs

public class ConnectionStringsConfigSection : IConfigSection
{
    public string ServerConnectionString { get; set; }
    public string LocalConnectionString { get; set; }

    public ConnectionStringsConfigSection()
    {
        // set default values to avoid null reference if
        // section is not present in appsettings.json
        ServerConnectionString = string.Empty;
        LocalConnectionString = string.Empty;
    }
}

And finally, a usage example:

Startup.cs

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // some stuff

        var app = Configuration.GetConfigSection<AppConfigSection>();
        var connectionStrings = Configuration.GetConfigSection<ConnectionStringsConfigSection>();

        services.AddDbContext<AppDbContext>(options =>
        {
            if (app.IsLocal)
            {
                options.UseSqlite(connectionStrings.LocalConnectionString);
            }
            else
            {
                options.UseSqlServer(connectionStrings.ServerConnectionString);
            }
        });

        // other stuff
    }
}

To make it neat, you can move above code into an extension method.

That's it, no hardcoded configuration keys.


There is another approach. In my example you see some business logic in repository class that I use with dependency injection in ASP .NET MVC Core 3.1.

And here I want to get connectiongString for that business logic because probably another repository will have access to another database at all.

This pattern allows you in the same business logic repository have access to different databases.

C#

public interface IStatsRepository
{
            IEnumerable<FederalDistrict> FederalDistricts();
}

class StatsRepository : IStatsRepository
{
   private readonly DbContextOptionsBuilder<EFCoreTestContext>
                optionsBuilder = new DbContextOptionsBuilder<EFCoreTestContext>();
   private readonly IConfigurationRoot configurationRoot;

   public StatsRepository()
   {
       IConfigurationBuilder configurationBuilder = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
       configurationRoot = configurationBuilder.Build();
   }

   public IEnumerable<FederalDistrict> FederalDistricts()
   {
        var conn = configurationRoot.GetConnectionString("EFCoreTestContext");
        optionsBuilder.UseSqlServer(conn);

        using (var ctx = new EFCoreTestContext(optionsBuilder.Options))
        { 
            return ctx.FederalDistricts.Include(x => x.FederalSubjects).ToList();
        }
    }
}

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "EFCoreTestContext": "Data Source=DESKTOP-GNJKL2V\\MSSQLSERVER2014;Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

In 3.1 there is a section already defined for "ConnectionStrings"

System.Configuration.ConnnectionStringSettings

Define:

  "ConnectionStrings": {
    "ConnectionString": "..."
  }

Register:

public void ConfigureServices(IServiceCollection services)
{
     services.Configure<ConnectionStringSettings>(Configuration.GetSection("ConnectionStrings"));
}

Inject:

public class ObjectModelContext : DbContext, IObjectModelContext
{

     private readonly ConnectionStringSettings ConnectionStringSettings;

    ...

     public ObjectModelContext(DbContextOptions<ObjectModelContext> options, IOptions<ConnectionStringSettings> setting) : base(options)
    {
          ConnectionStringSettings = setting.Value;
    }

    ...
}

Use:

   public static void ConfigureContext(DbContextOptionsBuilder optionsBuilder, ConnectionStringSettings connectionStringSettings)
    {
        if (optionsBuilder.IsConfigured == false)
        {
            optionsBuilder.UseLazyLoadingProxies()
                          .UseSqlServer(connectionStringSettings.ConnectionString);
        }
    }

ASP.NET Core (in my case 3.1) provides us with Constructor injections into Controllers, so you may simply add following constructor:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly IConfiguration m_config;

    public TestController(IConfiguration config)
    {
        m_config = config;
    }

    [HttpGet]
    public string Get()
    {
        //you can get connection string as follows
        string connectionString = m_config.GetConnectionString("Default")
    }
}

Here what appsettings.json may look like:

{
    "ConnectionStrings": {
        "Default": "YOUR_CONNECTION_STRING"
        }
}

See link for more info: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings

JSON

    {
      "ConnectionStrings": {
        "BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
      },
    }

C# Startup.cs

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

EDIT: aspnetcore, starting 3.1: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1



This is how I did it:

I added the connection string at appsettings.json

"ConnectionStrings": {
"conStr": "Server=MYSERVER;Database=MYDB;Trusted_Connection=True;MultipleActiveResultSets=true"},

I created a class called SqlHelper

public class SqlHelper
{
    //this field gets initialized at Startup.cs
    public static string conStr;

    public static SqlConnection GetConnection()
    {
        try
        {
            SqlConnection connection = new SqlConnection(conStr);
            return connection;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }
}

At the Startup.cs I used ConfigurationExtensions.GetConnectionString to get the connection,and I assigned it to SqlHelper.conStr

public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
        SqlHelper.connectionString = ConfigurationExtensions.GetConnectionString(this.Configuration, "conStr");
    }

Now wherever you need the connection string you just call it like this:

SqlHelper.GetConnection();

The posted answer is fine but didn't directly answer the same question I had about reading in a connection string. Through much searching I found a slightly simpler way of doing this.

In Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    // Add the whole configuration object here.
    services.AddSingleton<IConfiguration>(Configuration);
}

In your controller add a field for the configuration and a parameter for it on a constructor

private readonly IConfiguration configuration;

public HomeController(IConfiguration config) 
{
    configuration = config;
}

Now later in your view code you can access it like:

connectionString = configuration.GetConnectionString("DefaultConnection");