Can I move configuration from appsettings.json to database in an ASP.NET Core MVC application?
Asked Answered
C

1

14

I have this application that uses the appsettings.json to store some configurations like API addresses, tokens, paths to save files, etc.

We don't have DevOps, so for each change we do in the appsettings, we need to ask infrastructure team to deploy the changes to production.

That said, I'm thinking if it's possible to place some of this configuration in database and in the Startup constructor or in ConfigureServices to get this information from database and use it in the application.

That's just to don't need a new deploy every time I add a new key to the appsettings for example. I would simply create a new record in the database and the app will use this configuration as if it is in the appsettings.

Today we have this:

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

    Configuration = builder.Build();
}

And I want to know if there is viable, or possible something like this:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .GetConfigFromDataBase() /// And this will be the method to get from DB the dynamic configuration
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

Is it possible? Or I'm trying to reinvent the wheel?

Thank you in advance for your time !

Clockwise answered 21/2, 2020 at 0:3 Comment(3)
Perfect example from the docs to get you started. Custom configuration provider You would need to do some additional customization to get all the desired features but this should be enough to get you going.Amity
Thank you @Nkosi, we are going to try this solution, and I'll let you know if it worked.Clockwise
Thank you for the corrections @marc_s.Clockwise
B
17

First you create an entity for database.

public class SettingsEntity
{
    public Guid Id { get; set; }
    public string Key { get; set; }
    public string Value { get; set; }
}

Second a configuration source.

public class DatabaseConfigurationSource : IConfigurationSource
{
    public DatabaseConfigurationSource(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new DatabaseConfigurationProvider(Configuration);
    }
}

Third configuration provider.

public class DatabaseConfigurationProvider : ConfigurationProvider
{
    public DatabaseConfigurationProvider(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public override void Load()
    {
        using var context = new DbContext(CreateContextOptions());

        Data = context.Settings
            .ToDictionary(x => x.Key, x => x.Value);
    }

    private DbContextOptions<DbContext> CreateContextOptions()
    {
        var connectionString = Configuration.GetConnectionString("Database");

        return new DbContextOptionsBuilder<DbContext>()
            .UseSqlServer(connectionString)
            .Options;
    }

Fourth an extension for registering.

public static class DatabaseConfigurationBuilderExtensions
{
    public static IConfigurationBuilder AddDatabaseConfiguration(
        this IConfigurationBuilder builder)
    {
        var tempConfig = builder.Build();
        return builder.Add(new DatabaseConfigurationSource(tempConfig));
    }
}

Finally you register it in your Program.cs

 public static IWebHostBuilder CreateHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddDatabaseConfiguration();
        })
        .UseNLog();
Bonin answered 6/5, 2021 at 8:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.