Egyéni konfigurációszolgáltató implementálása a .NET-ben

Számos konfigurációszolgáltató érhető el gyakori konfigurációs forrásokhoz, például JSON-, XML- és INI-fájlokhoz. Előfordulhat, hogy egyéni konfigurációs szolgáltatót kell implementálnia, ha az egyik elérhető szolgáltató nem felel meg az alkalmazás igényeinek. Ebből a cikkből megtudhatja, hogyan implementálhat olyan egyéni konfigurációszolgáltatót, amely egy adatbázisra támaszkodik konfigurációs forrásként.

Egyéni konfigurációszolgáltató

A mintaalkalmazás bemutatja, hogyan hozhat létre alapszintű konfigurációszolgáltatót, amely beolvassa a konfigurációs kulcs-érték párokat egy adatbázisból az Entity Framework (EF) Core használatával.

A szolgáltató a következő jellemzőkkel rendelkezik:

  • A memóriabeli EF-adatbázist bemutató célokra használják.
    • Ha kapcsolati sztring igénylő adatbázist szeretne használni, szerezze be a kapcsolati sztring egy köztes konfigurációból.
  • A szolgáltató indításkor beolvassa az adatbázistáblát a konfigurációba. A szolgáltató nem kulcsonként kérdezi le az adatbázist.
  • A módosítás újrabetöltése nincs implementálva, így az adatbázis frissítése az alkalmazás elindítása után nem befolyásolja az alkalmazás konfigurációját.

Adjon meg egy Settings rekordtípus-entitást az adatbázis konfigurációs értékeinek tárolásához. Felvehet például egy Gépház.cs fájlt a Models mappába:

namespace CustomProvider.Example.Models;

public record Settings(string Id, string? Value);

A rekordtípusokról további információt a C# rekordtípusai című témakörben talál.

Adjon hozzá egy értéket EntityConfigurationContext a konfigurált értékek tárolásához és eléréséhez.

Szolgáltatók/EntityConfigurationContext.cs:

using CustomProvider.Example.Models;
using Microsoft.EntityFrameworkCore;

namespace CustomProvider.Example.Providers;

public sealed class EntityConfigurationContext(string? connectionString) : DbContext
{
    public DbSet<Settings> Settings => Set<Settings>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        _ = connectionString switch
        {
            { Length: > 0 } => optionsBuilder.UseSqlServer(connectionString),
            _ => optionsBuilder.UseInMemoryDatabase("InMemoryDatabase")
        };
    }
}

Felülbírálással OnConfiguring(DbContextOptionsBuilder) használhatja a megfelelő adatbázis-kapcsolatot. Ha például egy kapcsolati sztring biztosított, csatlakozhat az SQL Serverhez, különben memóriabeli adatbázisra támaszkodhat.

Hozzon létre egy implementálható osztályt IConfigurationSource.

Szolgáltatók/EntityConfigurationSource.cs:

using Microsoft.Extensions.Configuration;

namespace CustomProvider.Example.Providers;

public sealed class EntityConfigurationSource(
    string? connectionString) : IConfigurationSource
{
    public IConfigurationProvider Build(IConfigurationBuilder builder) =>
        new EntityConfigurationProvider(connectionString);
}

Hozza létre az egyéni konfigurációszolgáltatót a következőtől ConfigurationProvideröröklődve: . A konfigurációszolgáltató inicializálja az adatbázist, ha üres. Mivel a konfigurációs kulcsok nem érzéketlenek, az adatbázis inicializálásához használt szótár a kis- és nagybetűket megkülönböztető összehasonlítóval (StringComparer.OrdinalIgnoreCase) jön létre.

Szolgáltatók/EntityConfigurationProvider.cs:

using CustomProvider.Example.Models;
using Microsoft.Extensions.Configuration;

namespace CustomProvider.Example.Providers;

public sealed class EntityConfigurationProvider(
    string? connectionString)
    : ConfigurationProvider
{
    public override void Load()
    {
        using var dbContext = new EntityConfigurationContext(connectionString);

        dbContext.Database.EnsureCreated();

        Data = dbContext.Settings.Any()
            ? dbContext.Settings.ToDictionary(
                static c => c.Id,
                static c => c.Value, StringComparer.OrdinalIgnoreCase)
            : CreateAndSaveDefaultValues(dbContext);
    }

    static Dictionary<string, string?> CreateAndSaveDefaultValues(
        EntityConfigurationContext context)
    {
        var settings = new Dictionary<string, string?>(
            StringComparer.OrdinalIgnoreCase)
        {
            ["WidgetOptions:EndpointId"] = "b3da3c4c-9c4e-4411-bc4d-609e2dcc5c67",
            ["WidgetOptions:DisplayLabel"] = "Widgets Incorporated, LLC.",
            ["WidgetOptions:WidgetRoute"] = "api/widgets"
        };

        context.Settings.AddRange(
            [.. settings.Select(static kvp => new Settings(kvp.Key, kvp.Value))]);

        context.SaveChanges();

        return settings;
    }
}

A AddEntityConfiguration bővítménymetódus lehetővé teszi a konfigurációs forrás hozzáadását az alapul szolgáló ConfigurationManager példányhoz.

Bővítmények/ConfigurationManagerExtensions.cs:

using CustomProvider.Example.Providers;

namespace Microsoft.Extensions.Configuration;

public static class ConfigurationManagerExtensions
{
    public static ConfigurationManager AddEntityConfiguration(
        this ConfigurationManager manager)
    {
        var connectionString = manager.GetConnectionString("WidgetConnectionString");

        IConfigurationBuilder configBuilder = manager;
        configBuilder.Add(new EntityConfigurationSource(connectionString));

        return manager;
    }
}

Mivel a ConfigurationManager bővítménymetódus a kapcsolati sztring-konfigurációt is megvalósítja IConfigurationBuilderIConfigurationRoot, és hozzáadja a EntityConfigurationSource.

Az alábbi kód bemutatja, hogyan használható az egyéni EntityConfigurationProviderProgram.cs:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using CustomProvider.Example;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Configuration.AddEntityConfiguration();

builder.Services.Configure<WidgetOptions>(
    builder.Configuration.GetSection("WidgetOptions"));

using IHost host = builder.Build();

WidgetOptions options = host.Services.GetRequiredService<IOptions<WidgetOptions>>().Value;
Console.WriteLine($"DisplayLabel={options.DisplayLabel}");
Console.WriteLine($"EndpointId={options.EndpointId}");
Console.WriteLine($"WidgetRoute={options.WidgetRoute}");

await host.RunAsync();
// Sample output:
//    WidgetRoute=api/widgets
//    EndpointId=b3da3c4c-9c4e-4411-bc4d-609e2dcc5c67
//    DisplayLabel=Widgets Incorporated, LLC.

Szolgáltató felhasználása

Az egyéni konfigurációszolgáltató használatához használhatja a beállítási mintát. Ha a mintaalkalmazás a helyén van, adjon meg egy beállításobjektumot a widget beállításainak megjelenítéséhez.

namespace CustomProvider.Example;

public class WidgetOptions
{
    public required Guid EndpointId { get; set; }

    public required string DisplayLabel { get; set; } = null!;

    public required string WidgetRoute { get; set; } = null!;
}

Egy olyan konfigurációs példány regisztrálására irányuló Configure hívás, amely TOptions a rendszerhez kötődik.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using CustomProvider.Example;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Configuration.AddEntityConfiguration();

builder.Services.Configure<WidgetOptions>(
    builder.Configuration.GetSection("WidgetOptions"));

using IHost host = builder.Build();

WidgetOptions options = host.Services.GetRequiredService<IOptions<WidgetOptions>>().Value;
Console.WriteLine($"DisplayLabel={options.DisplayLabel}");
Console.WriteLine($"EndpointId={options.EndpointId}");
Console.WriteLine($"WidgetRoute={options.WidgetRoute}");

await host.RunAsync();
// Sample output:
//    WidgetRoute=api/widgets
//    EndpointId=b3da3c4c-9c4e-4411-bc4d-609e2dcc5c67
//    DisplayLabel=Widgets Incorporated, LLC.

Az előző kód a WidgetOptions konfiguráció szakaszából konfigurálja az "WidgetOptions" objektumot. Ez lehetővé teszi a beállítások mintáját, és megjeleníti az EF-beállítások függőségi injektálásra kész IOptions<WidgetOptions> ábrázolását. A beállításokat végső soron az egyéni konfigurációszolgáltató biztosítja.

Lásd még