1
votes

I have a .NET Core API project and I am trying to read some settings from the appsettings.json file.

The file looks like this:

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "ConnectionString": "abc"
}

and I am trying to read the ConnectionString setting like this:

ConfigurationManager.AppSettings["ConnectionString"];

but I get null, and apparently no app settings have been detected at all.

Edit:

Here is what I have now:

startup.cs

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

        public static IConfiguration Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<MyContext>();
            services.AddMvc();
            services.Configure<ConnectionStringSettings>(Configuration);
        }
}

ConnectionStringSettings.cs

 public class ConnectionStringSettings
    {
        public string ConnectionString { get; set; }
    }

appsettings.json

{
  "Logging": {
    ...
  },
  "ConnectionStrings": {
    "Debug": "abc"
  }
}

MyContext.cs public class MyContext : DbContext { string x;

    public MyContext() { }

    public MyContext(DbContextOptions<MyContext> options)
        : base(options) { }

    public MyContext(IOptions<ConnectionStringSettings> connectionStringSettings)
    {
        x = connectionStringSettings.Value.ConnectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
       //here I need my connection string
        optionsBuilder.UseMySql(connectionString);
    }

}

3
If I am not mistaken, ConfigurationManager is for use with the App.config files, and not the new appsettings.json files. You need to use the ConfigurationBuilder class as demonstrated in the following answer with IConfiguration - ColinM

3 Answers

3
votes

For .NET Core 2.x you need to set configuration up in startup as below

 public partial class Startup
    {
        public static IConfiguration Configuration;

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

Then access as below

Configuration.GetConnectionString("System")

You should also have your connection strings laid out as below.

"ConnectionStrings": {
    "System": "{connection String}"
  }

This will allow for multiple strings if required but work even if you only have the one.

EDIT: Once you've got the string, as ColinM says in his answer you need to register the string with a class which you can inject into your classes. In startup as below.

services.AddSingleton<IConnectionStringFactory, ConnectionStringFactory>(serviceProvider => new ConnectionStringFactory(Configuration.GetConnectionString("System")));

Your connection string class...

public class ConnectionStringFactory : IConnectionStringFactory
{
    private readonly string _connectionString;

    public ConnectionStringFactory(string connectionString)
    {
        _connectionString = connectionString;
    }

    public string Invoke()
    {
        return _connectionString;
    }
}

Inject into your class as so...

public class ClassName
{
    private readonly IConnectionStringFactory _connectionStringFactory;

public ClassName(IConnectionStringFactory connectionStringFactory)
    {
        _connectionStringFactory = connectionStringFactory;
    }

...
}

Your interface can be as simple as below

public interface IConnectionStringFactory
{
}

You don't need to use an interface but I'd recommend this approach

2
votes

Based on your requirement of setting the connection string in the OnConfiguring override in your context, you can use the following approach.

Update your appsettings.json configuration file to contain a new JSON object for your database options

{
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "DatabaseOptions": {
        "ConnectionString": "<Connection String>"
    }
}

Create your model class which your DatabaseOptions configuration will map to

public class DatabaseOptions
{
    public string ConnectionString { get; set; }
}

Then update your Startup class' ConfigureServices method to register an instance of IOptions<DatabaseOptions>

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

And finally, update your context constructor to inject your IOptions<DatabaseOptions> instance, ASP.NET Core will handle the dependency injection for you as long as you register your context in the service collection.

public class MyContext
{
    private readonly DatabaseOptions databaseOptions;

    public MyContext(DbContextOptions<MyContext> options, IOptions<DatabaseOptions> databaseOptions)
        : base(options)
    {
        this.databaseOptions = databaseOptions.Value;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        //here I need my connection string
        optionsBuilder.UseMySql(databaseOptions.ConnectionString);
    }
}

Personally, I don't like naming classes with Options in the name when that class is going to be used with IOptions<T>, but as developers we can spend a large time of coding just thinking of class and variable names, feel free to rename as you please.

0
votes

You should use Configuration in Startup =>

    public void ConfigureServices(IServiceCollection services)
    {
       var section = Configuration.GetSection("ConnectionString");
       var value= Configuration.GetValue<string>("ConnectionString")
    }