.NET'te özel yapılandırma sağlayıcısı uygulama

JSON, XML ve INI dosyaları gibi yaygın yapılandırma kaynakları için kullanılabilen birçok yapılandırma sağlayıcısı vardır. Kullanılabilir sağlayıcılardan biri uygulama gereksinimlerinize uygun olmadığında özel bir yapılandırma sağlayıcısı uygulamanız gerekebilir. Bu makalede, bir veritabanını yapılandırma kaynağı olarak kullanan bir özel yapılandırma sağlayıcısının nasıl uygulandığını öğreneceksiniz.

Özel yapılandırma sağlayıcı

Örnek uygulama, Entity Framework (EF) Core kullanarak bir veritabanından yapılandırma anahtar-değer çiftlerini okuyan temel bir yapılandırma sağlayıcısının nasıl oluşturulacağını gösterir.

Sağlayıcı, aşağıdaki özelliklere sahiptir:

  • EF bellek içi veritabanı, gösterim amacıyla kullanılır.
    • bağlantı dizesi gerektiren bir veritabanı kullanmak için ara yapılandırmadan bir bağlantı dizesi alın.
  • Sağlayıcı, başlangıçta bir veritabanı tablosunu yapılandırmaya okur. Sağlayıcı, veritabanını anahtar başına bazında sorgulamaz.
  • Değişiklikte yeniden yükleme uygulanmaz, bu nedenle uygulama başlatıldıktan sonra veritabanının güncelleştirilmesi uygulamanın yapılandırmasını etkilemez.

Yapılandırma değerlerini veritabanında depolamak için bir Settings kayıt türü varlığı tanımlayın. Örneğin, Modeller klasörünüzde bir Ayarlar.cs dosyası ekleyebilirsiniz:

namespace CustomProvider.Example.Models;

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

Kayıt türleri hakkında bilgi için bkz. C# dilinde kayıt türleri.

Yapılandırılan değerleri depolamak ve bunlara erişmek için bir EntityConfigurationContext ekleyin.

Sağlayıcılar/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")
        };
    }
}

Geçersiz kılarak OnConfiguring(DbContextOptionsBuilder) uygun veritabanı bağlantısını kullanabilirsiniz. Örneğin, bir bağlantı dizesi sağlandıysa SQL Server'a bağlanabilir, aksi takdirde bellek içi veritabanına güvenebilirsiniz.

IConfigurationSource uygulayan bir sınıf oluşturun.

Sağlayıcılar/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);
}

ConfigurationProvider öğesinden devralarak özel yapılandırma sağlayıcısını oluşturun. Yapılandırma sağlayıcısı, boş olduğunda veritabanını başlatır. Yapılandırma anahtarları büyük/küçük harfe duyarlı olmadığından, veritabanını başlatmak için kullanılan sözlük, büyük/küçük harfe duyarlı olmayan karşılaştırıcı ile (StringComparer.OrdinalIgnoreCase) oluşturulur.

Sağlayıcılar/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;
    }
}

Uzantı AddEntityConfiguration yöntemi, yapılandırma kaynağının temel alınan ConfigurationManager örneğe eklenmesine izin verir.

Uzantılar/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;
    }
}

ConfigurationManager hem uygulaması IConfigurationBuilder hem de IConfigurationRootolduğundan uzantı yöntemi bağlantı dizesi yapılandırmasına erişebilir ve öğesini ekleyebilirEntityConfigurationSource.

Aşağıdaki kod, Program.cs özel EntityConfigurationProviderözelliğinin nasıl kullanılacağını gösterir:

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.

Sağlayıcıyı kullanma

Özel yapılandırma sağlayıcısını kullanmak için seçenekler desenini kullanabilirsiniz. Örnek uygulama yerine yerleştirildiyse, pencere öğesi ayarlarını temsil eden bir seçenekler nesnesi tanımlayın.

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!;
}

Bir yapılandırma örneğini kaydetmek için Configure çağrı yapılır ve buna TOptions göre bağlanır.

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.

Yukarıdaki kod, yapılandırmanın bölümünden "WidgetOptions" nesnesini yapılandırıyorWidgetOptions. Bu, EF ayarlarının bağımlılık eklemeye hazır IOptions<WidgetOptions> gösterimini kullanıma seçerek seçenekler desenini etkinleştirir. Seçenekler nihai olarak özel yapılandırma sağlayıcısından sağlanır.

Ayrıca bkz.