You've already forked Extensions.Configuration.EntityFrameworkCore
Working implementation
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace RAIC.Extensions.Configuration.EntityFrameworkCore;
|
||||
|
||||
|
||||
internal interface IEntityFrameworkCoreDbSetConfigurationProvider : IConfigurationProvider
|
||||
{
|
||||
void OnReload();
|
||||
|
||||
bool Remove(string key);
|
||||
}
|
||||
|
||||
|
||||
internal class EntityFrameworkCoreDbSetConfigurationProvider<TDbContext, TSetting> : ConfigurationProvider, IEntityFrameworkCoreDbSetConfigurationProvider
|
||||
where TDbContext : DbContext, ISettingsDbContext<DbSet<TSetting>, TSetting>
|
||||
where TSetting : class, ISetting
|
||||
{
|
||||
private readonly IEntityFrameworkCoreDbSetConfigurationSource<TDbContext> _configurationSource;
|
||||
|
||||
internal EntityFrameworkCoreDbSetConfigurationProvider(IEntityFrameworkCoreDbSetConfigurationSource<TDbContext> configurationSource) : base()
|
||||
{
|
||||
_configurationSource = configurationSource;
|
||||
}
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
using var dbContext = _configurationSource.DbContextFactory!.CreateDbContext();
|
||||
Data = dbContext.Settings.ToDictionary(s => s.Key, s => (string?)s.Value);
|
||||
}
|
||||
|
||||
public bool Remove(string key) => Data.Remove(key);
|
||||
|
||||
public new void OnReload() => base.OnReload();
|
||||
}
|
||||
|
||||
internal interface IEntityFrameworkCoreDbSetConfigurationSource<TDbContext> where TDbContext : DbContext
|
||||
{
|
||||
internal IDbContextFactory<TDbContext> DbContextFactory { get; }
|
||||
}
|
||||
|
||||
internal class EntityFrameworkCoreDbSetConfigurationSource<TDbContext, TSetting> : IConfigurationSource, IEntityFrameworkCoreDbSetConfigurationSource<TDbContext>
|
||||
where TDbContext : DbContext, ISettingsDbContext<DbSet<TSetting>, TSetting>
|
||||
where TSetting : class, ISetting
|
||||
{
|
||||
public required IDbContextFactory<TDbContext> DbContextFactory { get; init; }
|
||||
|
||||
public IConfigurationProvider Build(IConfigurationBuilder builder)
|
||||
{
|
||||
return new EntityFrameworkCoreDbSetConfigurationProvider<TDbContext, TSetting>(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace RAIC.Extensions.Configuration.EntityFrameworkCore.Extensions;
|
||||
|
||||
public static class ConfigurationBuilderExtensions
|
||||
{
|
||||
public delegate DbContextOptionsBuilder<T> DbContextOptionsTransformer<T>(DbContextOptionsBuilder<T> transform) where T : DbContext;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <see cref="DbSet{}"/> off <typeparamref name="TDbContext"/> as a configuration provider to the <see cref="IConfigurationBuilder"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TDbContext">Type of the <see cref="DbContext"/> which implements <see cref="ISettingsDbContext{,}"/></typeparam>
|
||||
/// <typeparam name="TSetting">Concrete type which implements <see cref="ISetting"/></typeparam>
|
||||
/// <param name="optionsTransformer">
|
||||
/// a <see cref="DbContextOptionsTransformer{}"/> which configures your <see cref="DbContextOptions{}"/>. eg.
|
||||
/// <code>
|
||||
/// dbContextOptions => dbContextOptions.UseNpgsql(builder.Configuration.GetConnectionString("Default"))
|
||||
/// </code>
|
||||
/// </param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/></returns>
|
||||
public static IConfigurationBuilder AddDbSet<TDbContext, TSetting>(this IConfigurationBuilder builder, DbContextOptionsTransformer<TDbContext> optionsTransformer)
|
||||
where TDbContext : DbContext, ISettingsDbContext<DbSet<TSetting>, TSetting>
|
||||
where TSetting : class, ISetting
|
||||
{
|
||||
// DEBT: Find way to create non-pooled DbContextFactory since this is only a short lived usage
|
||||
var configurationSource = new EntityFrameworkCoreDbSetConfigurationSource<TDbContext, TSetting>()
|
||||
{
|
||||
DbContextFactory = new PooledDbContextFactory<TDbContext>(optionsTransformer(new DbContextOptionsBuilder<TDbContext>()).Options, poolSize: 1)
|
||||
};
|
||||
|
||||
return builder.Add(configurationSource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace RAIC.Extensions.Configuration.EntityFrameworkCore;
|
||||
|
||||
public interface ISettingsDbContext<out TSettingDbSet, out TSetting> : IDisposable
|
||||
where TSettingDbSet : DbSet<TSetting>
|
||||
where TSetting : class, ISetting
|
||||
{
|
||||
TSettingDbSet Settings { get; }
|
||||
}
|
||||
|
||||
|
||||
public interface ISetting
|
||||
{
|
||||
[Key]
|
||||
string Key { get; }
|
||||
|
||||
[Required]
|
||||
string Value { get; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="RAIC.Extensions.Configuration.EntityFrameworkCore.PostgreSQL" />
|
||||
<InternalsVisibleTo Include="RAIC.Extensions.Configuration.EntityFrameworkCore.SqlServer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
56
RAIC.Extensions.Configuration.EntityFrameworkCore/README.md
Normal file
56
RAIC.Extensions.Configuration.EntityFrameworkCore/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# RAIC.Extensions.Configuration.EntityFrameworkCore
|
||||
|
||||
This library is a `Microsoft.Extensions.Configuration.IConfigurationProvider` that reads settings from a `DbSet<ISetting> Settings` property
|
||||
present on your Entity Framework Core `DbContext`.
|
||||
|
||||
## Goals
|
||||
1. Usable with minimal constraints on your entity model
|
||||
1. Follows conventional configuration patterns
|
||||
1. `IOptionsMonitor` update support through optional opt-in services (see `RAIC.Extensions.Configuration.EntityFrameworkCore.PostgreSQL` & `RAIC.Extensions.Configuration.EntityFrameworkCore.SqlServer`)
|
||||
|
||||
|
||||
## Requirements
|
||||
* .NET 8
|
||||
|
||||
|
||||
## Gotchas
|
||||
* Setting values cannot be `null` (as signified by the `RequiredAttribute` on `ISetting.Value`)
|
||||
* Setting keys should not contain the `=` character (similar to `CommandLineConfigurationProvider` & `EnvironmentVariablesConfigurationProvider`)
|
||||
|
||||
|
||||
## Usage Example
|
||||
|
||||
```csharp
|
||||
|
||||
using RAIC.Extensions.Configuration.EntityFrameworkCore.Extensions;
|
||||
|
||||
public record Setting : ISetting
|
||||
{
|
||||
[Key]
|
||||
public required string Key { get; set; }
|
||||
|
||||
[Required]
|
||||
public required string Value { get; set; }
|
||||
}
|
||||
|
||||
public class MyDbContext(DbContextOptions<MyDbContext> options) : DbContext(options), ISettingsDbContext<DbSet<Setting>, Setting>
|
||||
{
|
||||
public DbSet<Setting> Settings { get; set; }
|
||||
}
|
||||
|
||||
var builder = Host.CreateApplicationBuilder(args) // or WebApplication.CreateBuilder(args);
|
||||
|
||||
// build an initial configuration
|
||||
builder.Configuration.AddJsonFile("appsettings.json")
|
||||
.AddUserSecrets<Program>(); // or whereever your connection string lives
|
||||
|
||||
// obtain connection string from preliminary config so can initialise other settings from DbSet
|
||||
builder.Configuration.AddDbSet<MyDbContext, Setting>(dbContextOptions => dbContextOptions.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
|
||||
|
||||
...
|
||||
|
||||
await builder.Build().RunAsync(); // use config as normal
|
||||
|
||||
```
|
||||
|
||||
Read more about [Configuration](https://docs.microsoft.com/en-us/dotnet/core/extensions/configuration) on the Microsoft Docs site.
|
||||
Reference in New Issue
Block a user