1.Define a Setting record type entity for storing configuration values in the database.
public record SystemConfiguration(long Id, string Key, string Value);
2.Add an context to store and access the configured values
using Microsoft.EntityFrameworkCore;
using To_Do_List.Configuration.Entities;
namespace To_Do_List.Configuration.DbContext;
public class SystemConfigurationContext : Microsoft.EntityFrameworkCore.DbContext
{
public DbSet<SystemConfiguration> SystemConfigurations => Set<SystemConfiguration>();
public SystemConfigurationContext(DbContextOptions<SystemConfigurationContext> options) : base(options)
{
}
}
3.Create a class that implements IConfigurationSource
using Microsoft.EntityFrameworkCore;
namespace To_Do_List.Configuration;
public class SystemConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _options;
public SystemConfigurationSource(Action<DbContextOptionsBuilder> options)
{
_options = options;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new SystemConfigurationProvider(_options);
}
}
4.Create the custom configuration provider by inheriting from ConfigurationProvider.
using Microsoft.EntityFrameworkCore;
using To_Do_List.Configuration.DbContext;
namespace To_Do_List.Configuration;
public class SystemConfigurationProvider : ConfigurationProvider
{
private Action<DbContextOptionsBuilder> _options { get; set; }
public SystemConfigurationProvider(Action<DbContextOptionsBuilder> options)
{
_options = options;
}
public override void Load()
{
var builder = new DbContextOptionsBuilder<SystemConfigurationContext>();
_options(builder);
using var dbContext = new SystemConfigurationContext(builder.Options);
if (dbContext == null || dbContext.SystemConfigurations == null)
{
throw new Exception("Null Db Context");
}
dbContext.Database.EnsureCreated();
// here depends on your configuration structure
Data = dbContext.SystemConfigurations.ToDictionary(c => c.Key, c => c.Value);
}
}
5.An AddEntityConfiguration extension methods permits adding the configuration sources to the underly ConfigurationManager
using Microsoft.EntityFrameworkCore;
namespace To_Do_List.Configuration.Extensions;
public static class SystemConfigurationExtensions
{
public static IConfigurationBuilder AddEFConfiguration(this IConfigurationBuilder builder,
Action<DbContextOptionsBuilder> options)
{
return builder.Add(new SystemConfigurationSource(options));
}
}
6.Register in the program.cs
builder.Configuration.AddEFConfiguration(options =>
{
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
}
);
7.At runtime, the DbContextOptions for SystemConfigurationContext is provided through the configuration in AddEFConfiguration (e.g., options.UseMySql(...)). However, during design time (when running dotnet ef migrations add), the EF Core tools do not execute your application and thus cannot access the IConfiguration or the Dependency Injection (DI) container. As a result, the tools are unable to construct the SystemConfigurationContext.
So add design factory(Do not upload this file to github):
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using To_Do_List.Configuration.DbContext;
namespace To_Do_List.Configuration.DesignFactory;
public class SystemConfigurationContextFactory : IDesignTimeDbContextFactory<SystemConfigurationContext>
{
public SystemConfigurationContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<SystemConfigurationContext>();
var connectionString = "Server=localhost;Database=ToDo;User=root;Password=12345678;";
optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
return new SystemConfigurationContext(optionsBuilder.Options);
}
}
8.As shown in Configuration provider, I add key and value directory to "DATA", So in system configure the key is "JWT" and the value is "{....}" the json. So it could not transform to JwtTokenOptions, we need to do it by ourself. Or when we provide configs to DATA we need to add [key:element1] [value1] [key:element2] [value2] to the DATA direction.
// get the json string
var jwtJson = builder.Configuration[JwtTokenOption.JwtKey];
if (!string.IsNullOrEmpty(jwtJson))
{
// transfor json string to jsonobj
var jwtOptions = JsonSerializer.Deserialize<JwtTokenOption>(jwtJson);
builder.Services.Configure<JwtTokenOption>(options =>
{
options.Issuer = jwtOptions.Issuer;
options.Audience = jwtOptions.Audience;
options.IssuerSigningKey = jwtOptions.IssuerSigningKey;
options.AccessTokenExpiresMinutes = jwtOptions.AccessTokenExpiresMinutes;
});
}
Top comments (0)