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

JSON, XML ve ıNı 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, yapılandırma kaynağı olarak bir veritabanını temel alan özel bir yapılandırma sağlayıcısını nasıl uygulayacağınızı öğreneceksiniz.

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

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

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

  • EF bellek içi veritabanı, tanıtım amacıyla kullanılır.
    • Bağlantı dizesi gerektiren bir veritabanını kullanmak için, bir ara yapılandırmadan bağlantı dizesi alın.
  • Sağlayıcı bir veritabanı tablosunu başlangıçta yapılandırmaya okur. Sağlayıcı, her anahtar temelinde veritabanını sorgulayamaz.
  • Değişiklik değişikliği uygulanmadı, bu nedenle uygulama başladıktan sonra veritabanını güncelleştirmek uygulamanın yapılandırmasını etkilemez.

SettingsYapılandırma değerlerini veritabanında depolamak için bir kayıt türü varlığı tanımlayın. örneğin, modeller klasörünüze 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# 9 ' da kayıt türleri.

Bir EntityConfigurationContext mağazaya ekleyin ve yapılandırılan değerlere erişin.

Sağlayıcılar/EntityConfigurationContext. cs:

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

namespace CustomProvider.Example.Providers;

public class EntityConfigurationContext : DbContext
{
    private readonly string _connectionString;

    public DbSet<Settings>? Settings { get; set; }

    public EntityConfigurationContext(string connectionString) =>
        _connectionString = connectionString;

    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ğlanmışsa SQL Server bağlanabilirsiniz, aksi takdirde bellek içi bir veritabanına güvenebilirsiniz.

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

Sağlayıcılar/EntityConfigurationSource. cs:

using Microsoft.Extensions.Configuration;

namespace CustomProvider.Example.Providers;

public class EntityConfigurationSource : IConfigurationSource
{
    private readonly string _connectionString;

    public EntityConfigurationSource(string connectionString) =>
        _connectionString = connectionString;

    public IConfigurationProvider Build(IConfigurationBuilder builder) =>
        new EntityConfigurationProvider(_connectionString);
}

Öğesinden devralarak özel yapılandırma sağlayıcısını oluşturun ConfigurationProvider . 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 duyarsız olduğundan, veritabanını başlatmak için kullanılan sözlük, büyük/küçük harf duyarsız karşılaştırıcı (StringComparer. OrdinalIgnoreCase) ile oluşturulur.

Sağlayıcılar/EntityConfigurationProvider. cs:

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

namespace CustomProvider.Example.Providers;

public class EntityConfigurationProvider : ConfigurationProvider
{
    private readonly string _connectionString;

    public EntityConfigurationProvider(string connectionString) =>
        _connectionString = connectionString;

    public override void Load()
    {
        using var dbContext = new EntityConfigurationContext(_connectionString);

        dbContext.Database.EnsureCreated();

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

    static IDictionary<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(kvp => new Settings(kvp.Key, kvp.Value))
                    .ToArray());

        context.SaveChanges();

        return settings;
    }
}

AddEntityConfigurationGenişletme yöntemi, yapılandırma kaynağının bir örneğe eklenmesine izin verir IConfigurationBuilder .

Extensions/ConfigurationBuilderExtensions. cs:

using CustomProvider.Example.Providers;

namespace Microsoft.Extensions.Configuration;

public static class ConfigurationBuilderExtensions
{
    public static IConfigurationBuilder AddEntityConfiguration(
        this IConfigurationBuilder builder)
    {
        var tempConfig = builder.Build();
        var connectionString =
            tempConfig.GetConnectionString("WidgetConnectionString");

        return builder.Add(new EntityConfigurationSource(connectionString));
    }
}

Önemli

Bağlantı dizesinin elde edilmesi için geçici bir yapılandırma kaynağı kullanılması önemlidir. Geçerli builder olan yapılandırması, ve çağırarak geçici olarak oluşturulur IConfigurationBuilder.Build() GetConnectionString . Bağlantı dizesini aldıktan sonra, verilen öğesini builder ekler EntityConfigurationSource connectionString .

Aşağıdaki kod, özel EntityConfigurationProvider program. cs' nin nasıl kullanılacağını gösterir:

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

namespace CustomProvider.Example
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).Build();

            var 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.

        static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((_, configuration) =>
                {
                    configuration.Sources.Clear();
                    configuration.AddEntityConfiguration();
                })
                .ConfigureServices((context, services) =>
                    services.Configure<WidgetOptions>(
                        context.Configuration.GetSection("WidgetOptions")));
    }
}

Sağlayıcıyı tüketme

Özel yapılandırma sağlayıcısını kullanmak için, Seçenekler modelinikullanabilirsiniz. Örnek uygulamayla birlikte, pencere öğesi ayarlarını temsil etmek için bir seçenek nesnesi tanımlayın.

namespace CustomProvider.Example;

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

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

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

ConfigureServicesSeçeneklerinin eşlemesini yapılandıran bir çağrı.

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

namespace CustomProvider.Example
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).Build();

            var 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.

        static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((_, configuration) =>
                {
                    configuration.Sources.Clear();
                    configuration.AddEntityConfiguration();
                })
                .ConfigureServices((context, services) =>
                    services.Configure<WidgetOptions>(
                        context.Configuration.GetSection("WidgetOptions")));
    }
}

Yukarıdaki kod, WidgetOptions nesneyi "WidgetOptions" yapılandırmanın bölümünden yapılandırır. Bu seçenek, EF ayarlarına yönelik bir bağımlılık ekleme hazırlığına neden olan seçenekler deseninin kullanılmasına izin vermez IOptions<WidgetOptions> . Seçenekler, sonunda özel yapılandırma sağlayıcısından sağlanır.

Ayrıca bkz.