ASP.NET Core'da seçenek deseni

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Rick Anderson tarafından.

Seçenekler düzeni, ilgili ayar gruplarına kesin olarak belirlenmiş erişim sağlamak için sınıfları kullanır. Yapılandırma ayarları senaryoya göre ayrı sınıflar halinde yalıtıldığında, uygulama iki önemli yazılım mühendisliği ilkesine uyar:

  • Kapsülleme:
    • Yapılandırma ayarlarına bağlı sınıflar yalnızca kullandıkları yapılandırma ayarlarına bağlıdır.
  • Endişelerin Ayrılması:
    • Uygulamanın farklı bölümleri için Ayarlar bağımlı veya birbirine bağlı değildir.

Seçenekler ayrıca yapılandırma verilerini doğrulamak için bir mekanizma sağlar. Daha fazla bilgi için Seçenekler doğrulama bölümüne bakın.

Bu makalede, ASP.NET Core'daki seçenekler deseni hakkında bilgi sağlanır. Konsol uygulamalarında seçenekler desenini kullanma hakkında bilgi için bkz . .NET'te seçenekler deseni.

Hiyerarşik yapılandırmayı bağlama

İlgili yapılandırma değerlerini okumanın tercih edilen yolu seçenekler desenini kullanmaktır. Örneğin, aşağıdaki yapılandırma değerlerini okumak için:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Aşağıdaki PositionOptions sınıflarını oluşturun:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Bir seçenekler sınıfı:

  • Soyut olmamalıdır.
  • Yapılandırmada karşılık gelen öğelere sahip türün genel okuma-yazma özelliklerine sahiptir.
  • Yapılandırmadaki eşleşen girişlere bağlı okuma-yazma özelliklerine sahiptir.
  • Alanları bağlı değil. Önceki örnekte, Position bağlı değildir. Position alanı kullanıldığından, "Position" öğesinin, sınıfı bir yapılandırma sağlayıcısına bağlarken uygulamada sabit kodlanmış olması gerekmez.

Aşağıdaki kod:

  • PositionOptions sınıfını, Position bölümüne bağlamak için ConfigurationBinder.Bind çağırır.
  • Position yapılandırma verisini görüntüler.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

ConfigurationBinder.Get<T> belirtilen türü bağlar ve döndürür. ConfigurationBinder.Get<T>, ConfigurationBinder.Bind kullanmaktan daha uygun olabilir. Aşağıdaki kod ConfigurationBinder.Get<T> öğesinin, PositionOptions sınıfıyla nasıl kullanılacağını göstermektedir:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Bind ayrıca soyut bir sınıfın birlesmesini de sağlar. soyut sınıfını SomethingWithANamekullanan aşağıdaki kodu göz önünde bulundurun:

namespace ConfigSample.Options;

public abstract class SomethingWithAName
{
    public abstract string? Name { get; set; }
}

public class NameTitleOptions(int age) : SomethingWithAName
{
    public const string NameTitle = "NameTitle";

    public override string? Name { get; set; }
    public string Title { get; set; } = string.Empty;

    public int Age { get; set; } = age;
}

Aşağıdaki kod yapılandırma değerlerini görüntüler NameTitleOptions :

public class Test33Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test33Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var nameTitleOptions = new NameTitleOptions(22);
        Configuration.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);

        return Content($"Title: {nameTitleOptions.Title} \n" +
                       $"Name: {nameTitleOptions.Name}  \n" +
                       $"Age: {nameTitleOptions.Age}"
                       );
    }
}

çağrısı Bind , çağrısından daha Get<>az katıdır:

  • Bind soyutun birlesmesini sağlar.
  • Get<> bir örneğin kendisini oluşturması gerekir.

Seçenekler Deseni

Seçenekler desenini kullanırken alternatif bir yaklaşım, Position bölümünü bağlamak ve bunu bağımlılık ekleme hizmet kapsayıcısına eklemektir. Aşağıdaki kodda PositionOptions, Configure ile hizmet kapsayıcıya eklenmiş ve yapılandırmaya bağlanmıştır:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

Aşağıdaki kod, önceki kodu kullanarak, konum seçeneklerini okur:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Önceki kodda, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunmaz. Uygulama başladıktan sonra değişiklikleri okumak için IOptionsSnapshot kullanın.

Seçenekler arabirimleri

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

  • Her istekte seçeneklerin yeniden derlenmesi gereken senaryolarda kullanışlıdır. Daha fazla bilgi için bkz . Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma.
  • Scoped olarak kaydedilir ve bu nedenle Bir Singleton hizmetine eklenemez.
  • Adlandırılmış seçenekleri destekler

IOptionsMonitor<TOptions>:

Yapılandırma sonrası senaryolar, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra seçeneklerin ayarlanmasını veya değiştirilmesini sağlar.

IOptionsFactory<TOptions> yeni seçenek örnekleri oluşturmakla sorumludur. Tek Create bir yöntemi vardır. Varsayılan uygulama tüm kayıtlı IConfigureOptions<TOptions> ve IPostConfigureOptions<TOptions> tüm yapılandırmaları önce çalıştırır, ardından yapılandırma sonrası. ve IConfigureOptions<TOptions> arasında IConfigureNamedOptions<TOptions> ayrım gerçekleştirir ve yalnızca uygun arabirimi çağırır.

IOptionsMonitorCache<TOptions> tarafından IOptionsMonitor<TOptions> örnekleri önbelleğe TOptions almak için kullanılır. değerin IOptionsMonitorCache<TOptions> yeniden derlenebilmesi için izleyicideki seçenek örneklerini geçersiz kılır (TryRemove). Değerler ile TryAddel ile tanıtılabilir. yöntemi Clear , tüm adlandırılmış örneklerin isteğe bağlı olarak yeniden oluşturulması gerektiğinde kullanılır.

Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma

kullanarak IOptionsSnapshot<TOptions>:

  • Seçenekler, erişime erişildiğinde istek başına bir kez hesaplanır ve isteğin ömrü boyunca önbelleğe alınır.
  • Kapsamlı bir hizmet olduğundan ve istek başına yeniden hesaplandığından önemli bir performans cezasına neden olabilir. Daha fazla bilgi için bu GitHub sorununa ve Yapılandırma bağlamasının performansını iyileştirme bölümüne bakın.
  • Yapılandırma değişiklikleri, güncelleştirilmiş yapılandırma değerlerini okumayı destekleyen yapılandırma sağlayıcıları kullanılırken uygulama başlatıldıktan sonra okunur.

ile IOptionsSnapshot arasındaki IOptionsMonitor fark şudur:

  • IOptionsMonitor , herhangi bir zamanda geçerli seçenek değerlerini alan bir Singleton hizmetidir ve bu da özellikle tek bağımlılıklarda yararlıdır.
  • IOptionsSnapshot Kapsamlı bir hizmettir ve nesne oluşturulurken seçeneklerin IOptionsSnapshot<T> anlık görüntüsünü sağlar. Seçenekler anlık görüntüleri, geçici ve kapsamlı bağımlılıklarla kullanılmak üzere tasarlanmıştır.

Aşağıdaki kodda kullanılır IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Aşağıdaki kod, şunlara bağlanan bir yapılandırma örneğini MyOptions kaydeder:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

var app = builder.Build();

Yukarıdaki kodda, uygulama başlatıldıktan sonra ON yapılandırma dosyasında yapılan değişiklikler JSokunur.

IOptionsMonitor

Aşağıdaki kod, ile bağlanan bir yapılandırma örneğini MyOptions kaydeder.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

var app = builder.Build();

Aşağıdaki örnek şunu kullanır IOptionsMonitor<TOptions>:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Adlandırılmış seçenekler IConfigureNamedOptions'ın kullanılmasını destekler

Adlandırılmış seçenekler:

  • Birden çok yapılandırma bölümü aynı özelliklere bağlandığında kullanışlıdır.
  • Büyük/küçük harfe duyarlıdır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

ve TopItem:Yearbağlamak TopItem:Month için iki sınıf oluşturmak yerine, her bölüm için aşağıdaki sınıf kullanılır:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; } = string.Empty;
    public string Model { get; set; } = string.Empty;
}

Aşağıdaki kod adlandırılmış seçenekleri yapılandırıyor:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

var app = builder.Build();

Aşağıdaki kod adlandırılmış seçenekleri görüntüler:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Tüm seçenekler adlandırılmış örneklerdir. IConfigureOptions<TOptions>örnekleri, örneğini hedefleme Options.DefaultName olarak değerlendirilir.string.Empty IConfigureNamedOptions<TOptions> ayrıca uygular IConfigureOptions<TOptions>. varsayılan uygulamasının IOptionsFactory<TOptions> her birini uygun şekilde kullanmak için mantığı vardır. null Adlandırılmış seçenek, belirli bir adlandırılmış örnek yerine tüm adlandırılmış örnekleri hedeflemek için kullanılır. ConfigureAll ve PostConfigureAll bu kuralı kullanın.

OptionsBuilder API'si

OptionsBuilder<TOptions> örnekleri yapılandırmak TOptions için kullanılır. OptionsBuilder sonraki tüm çağrılarda görüntülenmek yerine ilk AddOptions<TOptions>(string optionsName) çağrının yalnızca tek bir parametresi olduğundan adlandırılmış seçeneklerin oluşturulmasını kolaylaştırır. Seçenek doğrulama ve ConfigureOptions hizmet bağımlılıklarını kabul eden aşırı yüklemeler yalnızca aracılığıyla OptionsBuilderkullanılabilir.

OptionsBuilder, Seçenekler doğrulama bölümünde kullanılır.

Özel depo ekleme hakkında bilgi için bkz. Özel depo yapılandırmak için AddOptions kullanma.

Seçenekleri yapılandırmak için DI hizmetlerini kullanma

Hizmetlere bağımlılık eklemeden erişilirken seçenekler iki şekilde yapılandırılabilir:

  • üzerinde OptionsBuilder<TOptions>öğesine Configure bir yapılandırma temsilcisi geçirin. OptionsBuilder<TOptions> , seçenekleri yapılandırmak için beş adede kadar hizmetin kullanılmasına izin veren aşırı yüklemeler Configure sağlar:

    builder.Services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • veya IConfigureNamedOptions<TOptions> uygulayan IConfigureOptions<TOptions> bir tür oluşturun ve türü hizmet olarak kaydedin.

Hizmet oluşturmak daha karmaşık olduğundan, öğesine bir yapılandırma temsilcisi Configuregeçirmenizi öneririz. Tür oluşturmak, çağırırken Configureçerçevenin yaptıklarına eşdeğerdir. Çağrısı Configure , belirtilen genel IConfigureNamedOptions<TOptions>hizmet türlerini kabul eden bir oluşturucuya sahip olan geçici bir genel kaydeder.

Seçenekler doğrulaması

Seçenekler doğrulaması, seçenek değerlerinin doğrulanmasına olanak tanır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

Yapılandırma bölümüne bağlanmak için "MyConfig" aşağıdaki sınıf kullanılır ve birkaç DataAnnotations kural uygular:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

Aşağıdaki kod:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

var app = builder.Build();

ValidateDataAnnotations Uzantı yöntemi, Microsoft.Extensions.Options.DataAnnotations NuGet paketinde tanımlanır. SDK kullanan web uygulamaları için bu pakete Microsoft.NET.Sdk.Web paylaşılan çerçeveden örtük olarak başvurulur.

Aşağıdaki kod yapılandırma değerlerini veya doğrulama hatalarını görüntüler:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
            msg = $"Key1: {_config.Value.Key1} \n" +
                  $"Key2: {_config.Value.Key2} \n" +
                  $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

Aşağıdaki kod, temsilci kullanarak daha karmaşık bir doğrulama kuralı uygular:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

var app = builder.Build();

IValidateOptions<TOptions> ve IValidatableObject

Aşağıdaki sınıf şunu uygular IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string? vor = null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1!);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions , doğrulama kodunun sınıfın Program.cs dışına ve içine taşınmasını sağlar.

Yukarıdaki kod kullanılarak doğrulama aşağıdaki kodla etkinleştirilir Program.cs :

using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
                                        MyConfigOptions.MyConfig));

builder.Services.AddSingleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>();

var app = builder.Build();

Seçenekler doğrulaması da destekler IValidatableObject. Sınıfın kendi içinde sınıf düzeyinde doğrulama gerçekleştirmek için:

ValidateOnStart

Seçenek doğrulama, bir IOptions<TOptions>, IOptionsSnapshot<TOptions>veya IOptionsMonitor<TOptions> uygulaması ilk kez oluşturulduğunda çalışır. Seçenek doğrulamayı hevesle çalıştırmak için, uygulama başlatıldığında çağrısı ValidateOnStart yapın Program.cs:

builder.Services.AddOptions<MyConfigOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Yapılandırma sonrası seçenekler

ile IPostConfigureOptions<TOptions>yapılandırma sonrası ayarlayın. Yapılandırma sonrası, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra çalıştırılır:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

PostConfigure , adlandırılmış seçenekleri yapılandırma sonrası için kullanılabilir:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
    myOptions.Name = "post_configured_name_value";
    myOptions.Model = "post_configured_model_value";
});

var app = builder.Build();

Tüm yapılandırma örneklerini yapılandırma sonrası yapılandırmak için kullanın PostConfigureAll :

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

uygulamasındaki erişim seçenekleri Program.cs

'a erişmek IOptions<TOptions> veya IOptionsMonitor<TOptions> içinde Program.csöğesini aramak GetRequiredService için:WebApplication.Services

var app = builder.Build();

var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
    .CurrentValue.Option1;

Ek kaynaklar

Kirk Larkin ve Rick Anderson tarafından.

Seçenekler düzeni, ilgili ayar gruplarına kesin olarak belirlenmiş erişim sağlamak için sınıfları kullanır. Yapılandırma ayarları senaryoya göre ayrı sınıflar halinde yalıtıldığında, uygulama iki önemli yazılım mühendisliği ilkesine uyar:

  • Kapsülleme:
    • Yapılandırma ayarlarına bağlı sınıflar yalnızca kullandıkları yapılandırma ayarlarına bağlıdır.
  • Endişelerin Ayrılması:
    • Uygulamanın farklı bölümleri için Ayarlar bağımlı veya birbirine bağlı değildir.

Seçenekler ayrıca yapılandırma verilerini doğrulamak için bir mekanizma sağlar. Daha fazla bilgi için Seçenekler doğrulama bölümüne bakın.

Bu makalede, ASP.NET Core'daki seçenekler deseni hakkında bilgi sağlanır. Konsol uygulamalarında seçenekler desenini kullanma hakkında bilgi için bkz . .NET'te seçenekler deseni.

Hiyerarşik yapılandırmayı bağlama

İlgili yapılandırma değerlerini okumanın tercih edilen yolu seçenekler desenini kullanmaktır. Örneğin, aşağıdaki yapılandırma değerlerini okumak için:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Aşağıdaki PositionOptions sınıflarını oluşturun:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; } = String.Empty;
    public string Name { get; set; } = String.Empty;
}

Bir seçenekler sınıfı:

  • Genel bir parametresiz oluşturucu ile soyut olmamalıdır.
  • Türün tüm genel okuma-yazma özellikleri bağlıdır.
  • Alanlar bağlı değildir. Önceki örnekte, Position bağlı değildir. Position alanı kullanıldığından, "Position" öğesinin, sınıfı bir yapılandırma sağlayıcısına bağlarken uygulamada sabit kodlanmış olması gerekmez.

Aşağıdaki kod:

  • PositionOptions sınıfını, Position bölümüne bağlamak için ConfigurationBinder.Bind çağırır.
  • Position yapılandırma verisini görüntüler.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

ConfigurationBinder.Get<T> belirtilen türü bağlar ve döndürür. ConfigurationBinder.Get<T>, ConfigurationBinder.Bind kullanmaktan daha uygun olabilir. Aşağıdaki kod ConfigurationBinder.Get<T> öğesinin, PositionOptions sınıfıyla nasıl kullanılacağını göstermektedir:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions? positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Seçenekler desenini kullanırken alternatif bir yaklaşım, Position bölümünü bağlamak ve bunu bağımlılık ekleme hizmet kapsayıcısına eklemektir. Aşağıdaki kodda PositionOptions, Configure ile hizmet kapsayıcıya eklenmiş ve yapılandırmaya bağlanmıştır:

using ConfigSample.Options;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<PositionOptions>(
    builder.Configuration.GetSection(PositionOptions.Position));

var app = builder.Build();

Aşağıdaki kod, önceki kodu kullanarak, konum seçeneklerini okur:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Önceki kodda, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunmaz. Uygulama başladıktan sonra değişiklikleri okumak için IOptionsSnapshot kullanın.

Seçenekler arabirimleri

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

  • Her istekte seçeneklerin yeniden derlenmesi gereken senaryolarda kullanışlıdır. Daha fazla bilgi için bkz . Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma.
  • Scoped olarak kaydedilir ve bu nedenle Bir Singleton hizmetine eklenemez.
  • Adlandırılmış seçenekleri destekler

IOptionsMonitor<TOptions>:

Yapılandırma sonrası senaryolar, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra seçeneklerin ayarlanmasını veya değiştirilmesini sağlar.

IOptionsFactory<TOptions> yeni seçenek örnekleri oluşturmakla sorumludur. Tek Create bir yöntemi vardır. Varsayılan uygulama tüm kayıtlı IConfigureOptions<TOptions> ve IPostConfigureOptions<TOptions> tüm yapılandırmaları önce çalıştırır, ardından yapılandırma sonrası. ve IConfigureOptions<TOptions> arasında IConfigureNamedOptions<TOptions> ayrım gerçekleştirir ve yalnızca uygun arabirimi çağırır.

IOptionsMonitorCache<TOptions> tarafından IOptionsMonitor<TOptions> örnekleri önbelleğe TOptions almak için kullanılır. değerin IOptionsMonitorCache<TOptions> yeniden derlenebilmesi için izleyicideki seçenek örneklerini geçersiz kılır (TryRemove). Değerler ile TryAddel ile tanıtılabilir. yöntemi Clear , tüm adlandırılmış örneklerin isteğe bağlı olarak yeniden oluşturulması gerektiğinde kullanılır.

Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma

kullanarak IOptionsSnapshot<TOptions>:

  • Seçenekler, erişime erişildiğinde istek başına bir kez hesaplanır ve isteğin ömrü boyunca önbelleğe alınır.
  • Kapsamlı bir hizmet olduğundan ve istek başına yeniden hesaplandığından önemli bir performans cezasına neden olabilir. Daha fazla bilgi için bu GitHub sorununa ve Yapılandırma bağlamasının performansını iyileştirme bölümüne bakın.
  • Yapılandırma değişiklikleri, güncelleştirilmiş yapılandırma değerlerini okumayı destekleyen yapılandırma sağlayıcıları kullanılırken uygulama başlatıldıktan sonra okunur.

ile IOptionsSnapshot arasındaki IOptionsMonitor fark şudur:

  • IOptionsMonitor , herhangi bir zamanda geçerli seçenek değerlerini alan bir Singleton hizmetidir ve bu da özellikle tek bağımlılıklarda yararlıdır.
  • IOptionsSnapshot Kapsamlı bir hizmettir ve nesne oluşturulurken seçeneklerin IOptionsSnapshot<T> anlık görüntüsünü sağlar. Seçenekler anlık görüntüleri, geçici ve kapsamlı bağımlılıklarla kullanılmak üzere tasarlanmıştır.

Aşağıdaki kodda kullanılır IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Aşağıdaki kod, şunlara bağlanan bir yapılandırma örneğini MyOptions kaydeder:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

var app = builder.Build();

Yukarıdaki kodda, uygulama başlatıldıktan sonra ON yapılandırma dosyasında yapılan değişiklikler JSokunur.

IOptionsMonitor

Aşağıdaki kod, ile bağlanan bir yapılandırma örneğini MyOptions kaydeder.

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

var app = builder.Build();

Aşağıdaki örnek şunu kullanır IOptionsMonitor<TOptions>:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Adlandırılmış seçenekler IConfigureNamedOptions'ın kullanılmasını destekler

Adlandırılmış seçenekler:

  • Birden çok yapılandırma bölümü aynı özelliklere bağlandığında kullanışlıdır.
  • Büyük/küçük harfe duyarlıdır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

ve TopItem:Yearbağlamak TopItem:Month için iki sınıf oluşturmak yerine, her bölüm için aşağıdaki sınıf kullanılır:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; } = string.Empty;
    public string Model { get; set; } = string.Empty;
}

Aşağıdaki kod adlandırılmış seçenekleri yapılandırıyor:

using SampleApp.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

var app = builder.Build();

Aşağıdaki kod adlandırılmış seçenekleri görüntüler:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Tüm seçenekler adlandırılmış örneklerdir. IConfigureOptions<TOptions>örnekleri, örneğini hedefleme Options.DefaultName olarak değerlendirilir.string.Empty IConfigureNamedOptions<TOptions> ayrıca uygular IConfigureOptions<TOptions>. varsayılan uygulamasının IOptionsFactory<TOptions> her birini uygun şekilde kullanmak için mantığı vardır. null Adlandırılmış seçenek, belirli bir adlandırılmış örnek yerine tüm adlandırılmış örnekleri hedeflemek için kullanılır. ConfigureAll ve PostConfigureAll bu kuralı kullanın.

OptionsBuilder API'si

OptionsBuilder<TOptions> örnekleri yapılandırmak TOptions için kullanılır. OptionsBuilder sonraki tüm çağrılarda görüntülenmek yerine ilk AddOptions<TOptions>(string optionsName) çağrının yalnızca tek bir parametresi olduğundan adlandırılmış seçeneklerin oluşturulmasını kolaylaştırır. Seçenek doğrulama ve ConfigureOptions hizmet bağımlılıklarını kabul eden aşırı yüklemeler yalnızca aracılığıyla OptionsBuilderkullanılabilir.

OptionsBuilder, Seçenekler doğrulama bölümünde kullanılır.

Özel depo ekleme hakkında bilgi için bkz. Özel depo yapılandırmak için AddOptions kullanma.

Seçenekleri yapılandırmak için DI hizmetlerini kullanma

Hizmetlere bağımlılık eklemeden erişilirken seçenekler iki şekilde yapılandırılabilir:

  • üzerinde OptionsBuilder<TOptions>öğesine Configure bir yapılandırma temsilcisi geçirin. OptionsBuilder<TOptions> , seçenekleri yapılandırmak için beş adede kadar hizmetin kullanılmasına izin veren aşırı yüklemeler Configure sağlar:

    builder.Services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • veya IConfigureNamedOptions<TOptions> uygulayan IConfigureOptions<TOptions> bir tür oluşturun ve türü hizmet olarak kaydedin.

Hizmet oluşturmak daha karmaşık olduğundan, öğesine bir yapılandırma temsilcisi Configuregeçirmenizi öneririz. Tür oluşturmak, çağırırken Configureçerçevenin yaptıklarına eşdeğerdir. Çağrısı Configure , belirtilen genel IConfigureNamedOptions<TOptions>hizmet türlerini kabul eden bir oluşturucuya sahip olan geçici bir genel kaydeder.

Seçenekler doğrulaması

Seçenekler doğrulaması, seçenek değerlerinin doğrulanmasına olanak tanır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

Yapılandırma bölümüne bağlanmak için "MyConfig" aşağıdaki sınıf kullanılır ve birkaç DataAnnotations kural uygular:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

Aşağıdaki kod:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

var app = builder.Build();

ValidateDataAnnotations Uzantı yöntemi, Microsoft.Extensions.Options.DataAnnotations NuGet paketinde tanımlanır. SDK kullanan web uygulamaları için bu pakete Microsoft.NET.Sdk.Web paylaşılan çerçeveden örtük olarak başvurulur.

Aşağıdaki kod yapılandırma değerlerini veya doğrulama hatalarını görüntüler:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
            msg = $"Key1: {_config.Value.Key1} \n" +
                  $"Key2: {_config.Value.Key2} \n" +
                  $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

Aşağıdaki kod, temsilci kullanarak daha karmaşık bir doğrulama kuralı uygular:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
            .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

var app = builder.Build();

IValidateOptions<TOptions> ve IValidatableObject

Aşağıdaki sınıf şunu uygular IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string? vor = null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1!);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions , doğrulama kodunun sınıfın Program.cs dışına ve içine taşınmasını sağlar.

Yukarıdaki kod kullanılarak doğrulama aşağıdaki kodla etkinleştirilir Program.cs :

using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
                                        MyConfigOptions.MyConfig));

builder.Services.AddSingleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>();

var app = builder.Build();

Seçenekler doğrulaması da destekler IValidatableObject. Sınıfın kendi içinde sınıf düzeyinde doğrulama gerçekleştirmek için:

ValidateOnStart

Seçenek doğrulama, bir IOptions<TOptions>, IOptionsSnapshot<TOptions>veya IOptionsMonitor<TOptions> uygulaması ilk kez oluşturulduğunda çalışır. Seçenek doğrulamayı hevesle çalıştırmak için, uygulama başlatıldığında çağrısı ValidateOnStart yapın Program.cs:

builder.Services.AddOptions<MyConfigOptions>()
    .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Yapılandırma sonrası seçenekler

ile IPostConfigureOptions<TOptions>yapılandırma sonrası ayarlayın. Yapılandırma sonrası, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra çalıştırılır:

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

PostConfigure , adlandırılmış seçenekleri yapılandırma sonrası için kullanılabilir:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
    myOptions.Name = "post_configured_name_value";
    myOptions.Model = "post_configured_model_value";
});

var app = builder.Build();

Tüm yapılandırma örneklerini yapılandırma sonrası yapılandırmak için kullanın PostConfigureAll :

using OptionsValidationSample.Configuration;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

builder.Services.AddOptions<MyConfigOptions>()
                .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));

builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
    myOptions.Key1 = "post_configured_key1_value";
});

uygulamasındaki erişim seçenekleri Program.cs

'a erişmek IOptions<TOptions> veya IOptionsMonitor<TOptions> içinde Program.csöğesini aramak GetRequiredService için:WebApplication.Services

var app = builder.Build();

var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
    .CurrentValue.Option1;

Ek kaynaklar

Kirk Larkin ve Rick Anderson tarafından.

Seçenekler düzeni, ilgili ayar gruplarına kesin olarak belirlenmiş erişim sağlamak için sınıfları kullanır. Yapılandırma ayarları senaryoya göre ayrı sınıflar halinde yalıtıldığında, uygulama iki önemli yazılım mühendisliği ilkesine uyar:

  • Kapsülleme:
    • Yapılandırma ayarlarına bağlı sınıflar yalnızca kullandıkları yapılandırma ayarlarına bağlıdır.
  • Endişelerin Ayrılması:
    • Uygulamanın farklı bölümleri için Ayarlar bağımlı veya birbirine bağlı değildir.

Seçenekler ayrıca yapılandırma verilerini doğrulamak için bir mekanizma sağlar. Daha fazla bilgi için Seçenekler doğrulama bölümüne bakın.

Bu konu, ASP.NET Core'daki seçenekler deseni hakkında bilgi sağlar. Konsol uygulamalarında seçenekler desenini kullanma hakkında bilgi için bkz . .NET'te seçenekler deseni.

Örnek kodu görüntüleme veya indirme (indirme)

Hiyerarşik yapılandırmayı bağlama

İlgili yapılandırma değerlerini okumanın tercih edilen yolu seçenekler desenini kullanmaktır. Örneğin, aşağıdaki yapılandırma değerlerini okumak için:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Aşağıdaki PositionOptions sınıflarını oluşturun:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; }
    public string Name { get; set; }
}

Bir seçenekler sınıfı:

  • Genel bir parametresiz oluşturucu ile soyut olmamalıdır.
  • Türün tüm genel okuma-yazma özellikleri bağlıdır.
  • Alanlar bağlı değildir. Önceki örnekte, Position bağlı değildir. Position özelliği kullanıldığından, "Position" öğesinin, sınıfı bir yapılandırma sağlayıcısına bağlarken uygulamada sabit kodlanmış olması gerekmez.

Aşağıdaki kod:

  • PositionOptions sınıfını, Position bölümüne bağlamak için ConfigurationBinder.Bind çağırır.
  • Position yapılandırma verisini görüntüler.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

ConfigurationBinder.Get<T> belirtilen türü bağlar ve döndürür. ConfigurationBinder.Get<T>, ConfigurationBinder.Bind kullanmaktan daha uygun olabilir. Aşağıdaki kod ConfigurationBinder.Get<T> öğesinin, PositionOptions sınıfıyla nasıl kullanılacağını göstermektedir:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Seçenekler desenini kullanırken alternatif bir yaklaşım, Position bölümünü bağlamak ve bunu bağımlılık ekleme hizmet kapsayıcısına eklemektir. Aşağıdaki kodda PositionOptions, Configure ile hizmet kapsayıcıya eklenmiş ve yapılandırmaya bağlanmıştır:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(Configuration.GetSection(
                                        PositionOptions.Position));
    services.AddRazorPages();
}

Aşağıdaki kod, önceki kodu kullanarak, konum seçeneklerini okur:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Önceki kodda, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunmaz. Uygulama başladıktan sonra değişiklikleri okumak için IOptionsSnapshot kullanın.

Seçenekler arabirimleri

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

  • Her istekte seçeneklerin yeniden derlenmesi gereken senaryolarda kullanışlıdır. Daha fazla bilgi için bkz . Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma.
  • Kapsamlı olarak kaydedilir ve bu nedenle bir Singleton hizmetine eklenemez.
  • Adlandırılmış seçenekleri destekler

IOptionsMonitor<TOptions>:

Yapılandırma sonrası senaryolar, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra seçeneklerin ayarlanmasını veya değiştirilmesini sağlar.

IOptionsFactory<TOptions> yeni seçenek örnekleri oluşturmakla sorumludur. Tek Create bir yöntemi vardır. Varsayılan uygulama tüm kayıtlı IConfigureOptions<TOptions> ve IPostConfigureOptions<TOptions> tüm yapılandırmaları önce çalıştırır, ardından yapılandırma sonrası. ve IConfigureOptions<TOptions> arasında IConfigureNamedOptions<TOptions> ayrım gerçekleştirir ve yalnızca uygun arabirimi çağırır.

IOptionsMonitorCache<TOptions> tarafından IOptionsMonitor<TOptions> örnekleri önbelleğe TOptions almak için kullanılır. değerin IOptionsMonitorCache<TOptions> yeniden derlenebilmesi için izleyicideki seçenek örneklerini geçersiz kılır (TryRemove). Değerler ile TryAddel ile tanıtılabilir. yöntemi Clear , tüm adlandırılmış örneklerin isteğe bağlı olarak yeniden oluşturulması gerektiğinde kullanılır.

Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma

kullanılarak IOptionsSnapshot<TOptions>, seçenekler istek başına bir kez hesaplanır ve isteğin ömrü boyunca önbelleğe alınır. Yapılandırma değişiklikleri, güncelleştirilmiş yapılandırma değerlerini okumayı destekleyen yapılandırma sağlayıcıları kullanılırken uygulama başlatıldıktan sonra okunur.

ile IOptionsSnapshot arasındaki IOptionsMonitor fark şudur:

  • IOptionsMonitor , herhangi bir zamanda geçerli seçenek değerlerini alan bir Singleton hizmetidir ve bu da özellikle tek bağımlılıklarda yararlıdır.
  • IOptionsSnapshot Kapsamlı bir hizmettir ve nesne oluşturulurken seçeneklerin IOptionsSnapshot<T> anlık görüntüsünü sağlar. Seçenekler anlık görüntüleri, geçici ve kapsamlı bağımlılıklarla kullanılmak üzere tasarlanmıştır.

Aşağıdaki kodda kullanılır IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Aşağıdaki kod, şunlara bağlanan bir yapılandırma örneğini MyOptions kaydeder:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Yukarıdaki kodda, uygulama başlatıldıktan sonra ON yapılandırma dosyasında yapılan değişiklikler JSokunur.

IOptionsMonitor

Aşağıdaki kod, ile bağlanan bir yapılandırma örneğini MyOptions kaydeder.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Aşağıdaki örnek şunu kullanır IOptionsMonitor<TOptions>:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Önceki kodda, varsayılan olarak, uygulama başladıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.

Adlandırılmış seçenekler IConfigureNamedOptions'ın kullanılmasını destekler

Adlandırılmış seçenekler:

  • Birden çok yapılandırma bölümü aynı özelliklere bağlandığında kullanışlıdır.
  • Büyük/küçük harfe duyarlıdır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

ve TopItem:Yearbağlamak TopItem:Month için iki sınıf oluşturmak yerine, her bölüm için aşağıdaki sınıf kullanılır:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; }
    public string Model { get; set; }
}

Aşağıdaki kod adlandırılmış seçenekleri yapılandırıyor:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<TopItemSettings>(TopItemSettings.Month,
                                       Configuration.GetSection("TopItem:Month"));
    services.Configure<TopItemSettings>(TopItemSettings.Year,
                                        Configuration.GetSection("TopItem:Year"));

    services.AddRazorPages();
}

Aşağıdaki kod adlandırılmış seçenekleri görüntüler:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Tüm seçenekler adlandırılmış örneklerdir. IConfigureOptions<TOptions>örnekleri, örneğini hedefleme Options.DefaultName olarak değerlendirilir.string.Empty IConfigureNamedOptions<TOptions> ayrıca uygular IConfigureOptions<TOptions>. varsayılan uygulamasının IOptionsFactory<TOptions> her birini uygun şekilde kullanmak için mantığı vardır. null Adlandırılmış seçenek, belirli bir adlandırılmış örnek yerine tüm adlandırılmış örnekleri hedeflemek için kullanılır. ConfigureAll ve PostConfigureAll bu kuralı kullanın.

OptionsBuilder API'si

OptionsBuilder<TOptions> örnekleri yapılandırmak TOptions için kullanılır. OptionsBuilder sonraki tüm çağrılarda görüntülenmek yerine ilk AddOptions<TOptions>(string optionsName) çağrının yalnızca tek bir parametresi olduğundan adlandırılmış seçeneklerin oluşturulmasını kolaylaştırır. Seçenek doğrulama ve ConfigureOptions hizmet bağımlılıklarını kabul eden aşırı yüklemeler yalnızca aracılığıyla OptionsBuilderkullanılabilir.

OptionsBuilder, Seçenekler doğrulama bölümünde kullanılır.

Özel depo ekleme hakkında bilgi için bkz. Özel depo yapılandırmak için AddOptions kullanma.

Seçenekleri yapılandırmak için DI hizmetlerini kullanma

Hizmetlere bağımlılık eklemeden erişilirken seçenekler iki şekilde yapılandırılabilir:

  • üzerinde OptionsBuilder<TOptions>öğesine Configure bir yapılandırma temsilcisi geçirin. OptionsBuilder<TOptions> , seçenekleri yapılandırmak için beş adede kadar hizmetin kullanılmasına izin veren aşırı yüklemeler Configure sağlar:

    services.AddOptions<MyOptions>("optionalName")
        .Configure<Service1, Service2, Service3, Service4, Service5>(
            (o, s, s2, s3, s4, s5) => 
                o.Property = DoSomethingWith(s, s2, s3, s4, s5));
    
  • veya IConfigureNamedOptions<TOptions> uygulayan IConfigureOptions<TOptions> bir tür oluşturun ve türü hizmet olarak kaydedin.

Hizmet oluşturmak daha karmaşık olduğundan, öğesine bir yapılandırma temsilcisi Configuregeçirmenizi öneririz. Tür oluşturmak, çağırırken Configureçerçevenin yaptıklarına eşdeğerdir. Çağrısı Configure , belirtilen genel IConfigureNamedOptions<TOptions>hizmet türlerini kabul eden bir oluşturucuya sahip olan geçici bir genel kaydeder.

Seçenekler doğrulaması

Seçenekler doğrulaması, seçenek değerlerinin doğrulanmasına olanak tanır.

Aşağıdaki appsettings.json dosyasını göz önünde bulundurun:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

Aşağıdaki sınıf yapılandırma bölümüne bağlanır "MyConfig" ve birkaç DataAnnotations kural uygular:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

Aşağıdaki kod:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions<MyConfigOptions>()
            .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

        services.AddControllersWithViews();
    }

ValidateDataAnnotations Uzantı yöntemi, Microsoft.Extensions.Options.DataAnnotations NuGet paketinde tanımlanır. SDK kullanan web uygulamaları için bu pakete Microsoft.NET.Sdk.Web paylaşılan çerçeveden örtük olarak başvurulur.

Aşağıdaki kod yapılandırma değerlerini veya doğrulama hatalarını görüntüler:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;

        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
             msg = $"Key1: {_config.Value.Key1} \n" +
                   $"Key2: {_config.Value.Key2} \n" +
                   $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

Aşağıdaki kod, temsilci kullanarak daha karmaşık bir doğrulama kuralı uygular:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions<MyConfigOptions>()
        .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
        .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

    services.AddControllersWithViews();
}

Karmaşık doğrulama için IValidateOptions

Aşağıdaki sınıf şunu uygular IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string vor=null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions , doğrulama kodunun sınıfın StartUp dışına ve içine taşınmasını sağlar.

Yukarıdaki kod kullanılarak doğrulama aşağıdaki kodla etkinleştirilir Startup.ConfigureServices :

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyConfigOptions>(Configuration.GetSection(
                                        MyConfigOptions.MyConfig));
    services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>());
    services.AddControllersWithViews();
}

Yapılandırma sonrası seçenekler

ile IPostConfigureOptions<TOptions>yapılandırma sonrası ayarlayın. Yapılandırma sonrası, tüm IConfigureOptions<TOptions> yapılandırma gerçekleştikten sonra çalıştırılır:

services.PostConfigure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

PostConfigure , adlandırılmış seçenekleri yapılandırma sonrası için kullanılabilir:

services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Tüm yapılandırma örneklerini yapılandırma sonrası yapılandırmak için kullanın PostConfigureAll :

services.PostConfigureAll<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Başlatma sırasında seçeneklere erişme

IOptions<TOptions> ve IOptionsMonitor<TOptions> içinde kullanılabilir Startup.Configure, çünkü hizmetler yöntem yürütülmeden Configure önce oluşturulur.

public void Configure(IApplicationBuilder app, 
    IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}

veya IOptionsMonitor<TOptions> içinde Startup.ConfigureServiceskullanmayınIOptions<TOptions>. Hizmet kayıtlarının sıralanması nedeniyle tutarsız bir seçenek durumu olabilir.

Options.ConfigurationExtensions NuGet paketi

Microsoft.Extensions.Options.ConfigurationExtensions paketine ASP.NET Core uygulamalarında örtük olarak başvurulur.