ASP.NET Core'da seçenek deseni

Note

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

Warning

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 10 sürümüne bakın.

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 birbirine bağımlı değildir.

Seçenekler ayrıca , Seçenekler doğrulama bölümünde açıklanan yapılandırma verilerini doğrulamak için bir mekanizma sağlar.

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.

Bu makaledeki örnekler, sınıflara hizmet ekleme konusunda genel bir anlayışa dayanır. Daha fazla bilgi için, bkz. ASP.NET Core'de bağımlılık ekleme. Örnekler, Blazor'nin Razor bileşenlerine dayanır. Sayfa örneklerini görmek Razor için bu makalenin 7.0 sürümüne bakın. Bu makalenin .NET 8 veya sonraki sürümlerindeki örneklerde birincil oluşturucular (Birincil oluşturucular (C# Kılavuzu)) ve .NET derleyici null durumu statik çözümlemesi ile null atanabilir başvuru türleri (NRTs) kullanılır.

Seçenekler desenini kullanma

Bir çalışanın adı ve kuruluşun konumundaki unvanıyla ilgili verileri içeren bir uygulama ayarları dosyasından (örneğin, appsettings.json) aşağıdaki JSON yapılandırma verilerini göz önünde bulundurun:

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

Aşağıdaki PositionOptions seçenekler sınıfı:

  • POCO, özelliklere sahip basit bir .NET sınıfıdır. Seçenekler sınıfı soyut bir sınıf olmamalıdır.
  • Yapılandırma verilerindeki ilgili girişlerle eşleşen genel okuma-yazma özelliklerine sahiptir.
  • Alanı () bağlı . alanı, Position sınıfı bir yapılandırma sağlayıcısına bağlarken uygulamadaki dizenin "Position" sabit kodlamasını önlemek için kullanılır.

PositionOptions.cs:

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

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

Aşağıdaki örnek:

  • ConfigurationBinder.Bind sınıfını PositionOptions bölümüne bağlamak için çağırır.
  • Position yapılandırma verisini görüntüler.

BasicOptions.razor:

@page "/basic-options"
@inject IConfiguration Config

Name: @positionOptions?.Name<br>
Title: @positionOptions?.Title

@code {
    private PositionOptions? positionOptions;

    protected override void OnInitialized()
    {
        positionOptions = new PositionOptions();
        Config.GetSection(PositionOptions.Position).Bind(positionOptions);
    }
}

BasicOptions.cshtml:

@page
@model RazorPagesSample.Pages.BasicOptionsModel
@{
}

BasicOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPagesSample.Pages;

public class BasicOptionsModel : PageModel
{
    private readonly IConfiguration _config;

    public BasicOptionsModel(IConfiguration config)
    {
        _config = config;
    }

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

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

Çıktı:

Name: Joe Smith
Title: Editor

Uygulama başlatıldıktan sonra, uygulama ayarları dosyasındaki JSON yapılandırmasında yapılan değişiklikler okunur. Davranışı göstermek için, uygulama ayarları dosyasındaki bir veya her iki yapılandırma değerini değiştirin ve uygulamayı yeniden başlatmadan sayfayı yeniden yükleyin.

Bind soyut bir sınıfın örneklenmesine izin verir. soyut sınıfını AbstractClassWithNamekullanan aşağıdaki örneği göz önünde bulundurun.

NameTitleOptions.cs:

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

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

    public override string? Name { get; set; }
    public string? Title { get; set; }
    public int Age { get; set; } = age;
}

JSON yapılandırması:

"NameTitle": {
  "Name": "Sally Jones",
  "Title": "Writer"
}

Aşağıdaki örnekte yapılandırma değerleri görüntülenir NameTitleOptions .

AbstractClassOptions.razor:

@page "/abstract-class-options"
@inject IConfiguration Config

Name: @nameTitleOptions?.Name<br>
Title: @nameTitleOptions?.Title<br>
Age: @nameTitleOptions?.Age

@code {
    private NameTitleOptions? nameTitleOptions;

    protected override void OnInitialized()
    {
        nameTitleOptions = new NameTitleOptions(22);
        Config.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);
    }
}

AbstractClassOptions.cshtml:

@page
@model RazorPagesSample.Pages.AbstractClassOptionsModel
@{
}

AbstractClassOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPagesSample.Pages;

public class AbstractClassOptionsModel : PageModel
{
    private readonly IConfiguration _config;

    public AbstractClassOptionsModel(IConfiguration config)
    {
        _config = config;
    }

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

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

Çıktı:

Name: Sally Jones
Title: Writer
Age: 22

ConfigurationBinder.Get belirtilen türü bağlar ve döndürür. Aşağıdaki örnekte Get'nin PositionOptions sınıfıyla nasıl kullanılacağı gösterilmektedir.

GetOptions.razor:

@page "/get-options"
@inject IConfiguration Config

Name: @positionOptions?.Name<br>
Title: @positionOptions?.Title

@code {
    private PositionOptions? positionOptions;

    protected override void OnInitialized() =>
        positionOptions = Config.GetSection(PositionOptions.Position)
            .Get<PositionOptions>();
}

GetOptions.cshtml:

@page
@model RazorPagesSample.Pages.GetOptionsModel
@{
}

GetOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPagesSample.Pages;

public class GetOptionsModel : PageModel
{
    private readonly IConfiguration _config;

    public GetOptionsModel(IConfiguration config)
    {
        _config = config;
    }

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

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

Çıktı:

Name: Joe Smith
Title: Editor

Uygulama başlatıldıktan sonra, uygulama ayarları dosyasındaki JSON yapılandırmasında yapılan değişiklikler okunur. Davranışı göstermek için, uygulama ayarları dosyasındaki bir veya her iki yapılandırma değerini değiştirin ve uygulamayı yeniden başlatmadan sayfayı yeniden yükleyin.

ile ConfigurationBinder.Bindarasındaki ConfigurationBinder.Get farkların özeti:

  • Get genellikle Bind kullanmaktan daha kullanışlıdır çünkü Get nesnenin yeni bir örneğini oluşturur ve döndürürken, Bind genellikle başka bir kod satırı tarafından oluşturulan mevcut bir nesne örneğinin özelliklerini doldurur.
  • Bind bir soyut sınıfın birleştirilmiş olmasına izin verirken, Get seçenekler türünün yalnızca soyut olmayan bir örneğini oluşturabilir.

Bağımlılık enjeksiyonu hizmeti kapsayıcısına seçenekleri bağlama

Aşağıdaki örnekte, PositionOptions ve Configure yapılandırmayla ilişkilendirilmiş hizmet kapsayıcısına eklenir.

JSON yapılandırması:

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

PositionOptions.cs:

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

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

Hizmetlerin uygulamanın Program dosyasına bağımlılık ekleme için kaydedildiği yer:

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

Aşağıdaki örnek konum seçeneklerini okur.

DIOptions.razor:

@page "/di-options"
@using Microsoft.Extensions.Options
@inject IOptions<PositionOptions> Options

Name: @Options.Value.Name<br>
Title: @Options.Value.Title

DIOptions.cshtml:

@page
@model RazorPagesSample.Pages.DIOptionsModel
@{
}

DIOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class DIOptionsModel : PageModel
{
    private readonly IOptions<PositionOptions> _options;

    public DIOptionsModel(IOptions<PositionOptions> options)
    {
        _options = options;
    }

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

Çıktı:

Name: Joe Smith
Title: Editor

Önceki kod için, uygulama başlatıldıktan sonra uygulama ayarları dosyasında JSON yapılandırmasında yapılan değişiklikler okunmuyor . Uygulama başlatıldıktan sonra değişiklikleri okumak için kullanın IOptionsSnapshot.

Seçenekler arabirimleri

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

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. Bir Create yöntemi vardır. Varsayılan uygulama, kayıtlı IConfigureOptions<TOptions> ve IPostConfigureOptions<TOptions>'in tüm yapılandırmalarını önce, ardından yapılandırma sonrası işlemlerini çalıştırır. IConfigureNamedOptions<TOptions> ile IConfigureOptions<TOptions> arasında ayrım yapar ve yalnızca uygun arabirimi çağırır.

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

kullanarak IOptionsSnapshot<TOptions>:

ile IOptionsMonitor arasındaki IOptionsSnapshot<TOptions> fark şudur:

  • IOptionsMonitor<TOptions> , her zaman geçerli seçenek değerlerini alan tekil bir hizmettir ve bu da özellikle tek bağımlılıklarda yararlıdır.
  • IOptionsSnapshot<TOptions> 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üler, geçici ve ölçeklendirilmiş bağımlılıklarla kullanılmak üzere tasarlanmıştır.

ASP.NET Core çalışma zamanı, OptionsCache<TOptions>'yı, seçenekler örneği oluşturulduktan sonra önbelleğe almak için kullanır.

JSON yapılandırması:

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

PositionOptions.cs:

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

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

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

SnapshotOptions.razor:

@page "/snapshot-options"
@using Microsoft.Extensions.Options
@inject IOptionsSnapshot<PositionOptions> Options

Name: @Options.Value.Name<br>
Title: @Options.Value.Title

SnapshotOptions.cshtml:

@page
@model RazorPagesSample.Pages.SnapshotOptionsModel
@{
}

SnapshotOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class SnapshotOptionsModel : PageModel
{
    private readonly IOptionsSnapshot<PositionOptions> _options;

    public SnapshotOptionsModel(IOptionsSnapshot<PositionOptions> options)
    {
        _options = options;
    }

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

Bağımlılık ekleme için hizmetlerin kaydedildiği durumlarda, aşağıdaki örnek bir yapılandırma örneğini kaydeder ve PositionOptions ile bağlar.

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

Çıktı:

Name: Joe Smith
Title: Editor

Uygulama başlatıldıktan sonra, uygulama ayarları dosyasındaki JSON yapılandırmasında yapılan değişiklikler okunur. Davranışı göstermek için, uygulama ayarları dosyasındaki bir veya her iki yapılandırma değerini değiştirin ve uygulamayı yeniden başlatmadan sayfayı yeniden yükleyin.

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

IOptionsMonitor<TOptions>, TOptions örneklerinin seçeneklerini almak ve seçenek bildirimlerini yönetmek için kullanılır.

ile IOptionsMonitor<TOptions> arasındaki IOptionsSnapshot fark şudur:

  • IOptionsMonitor<TOptions> , her zaman geçerli seçenek değerlerini alan tekil bir hizmettir ve bu da özellikle tek bağımlılıklarda yararlıdır.
  • IOptionsSnapshot<TOptions> 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üler, geçici ve ölçeklendirilmiş bağımlılıklarla kullanılmak üzere tasarlanmıştır.

IOptionsMonitorCache<TOptions>, IOptionsMonitor<TOptions> tarafından TOptions örneklerini önbelleğe almak için kullanılır. IOptionsMonitorCache<TOptions>.TryRemove değerin yeniden hesaplanabilmesi için monitördeki seçenek örneklerini geçersiz kılar. Değerler el ile IOptionsMonitorCache<TOptions>.TryAdd 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.

JSON yapılandırması:

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

PositionOptions.cs:

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

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

Bağımlılık ekleme için hizmetlerin kaydedildiği durumlarda, aşağıdaki örnek bir yapılandırma örneğini kaydeder ve PositionOptions ile bağlar.

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

Aşağıdaki örnekte IOptionsMonitor<TOptions>kullanılır.

MonitorOptions.razor:

@page "/monitor-options"
@using Microsoft.Extensions.Options
@inject IOptionsMonitor<PositionOptions> Options

Name: @Options.CurrentValue.Name<br>
Title: @Options.CurrentValue.Title

MonitorOptions.cshtml:

@page
@model RazorPagesSample.Pages.MonitorOptionsModel
@{
}

MonitorOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class MonitorOptionsModel : PageModel
{
    private readonly IOptionsMonitor<PositionOptions> _options;

    public MonitorOptionsModel(IOptionsMonitor<PositionOptions> options)
    {
        _options = options;
    }

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

Çıktı:

Name: Joe Smith
Title: Editor

Uygulama başlatıldıktan sonra, uygulama ayarları dosyasındaki JSON yapılandırmasında yapılan değişiklikler okunur. Davranışı göstermek için, uygulama ayarları dosyasındaki bir veya her iki yapılandırma değerini değiştirin ve uygulamayı yeniden başlatmadan sayfayı yeniden yükleyin.

kullanarak bir yapılandırma özelliği için özel bir anahtar adı belirtin ConfigurationKeyName

Varsayılan olarak, options sınıfının özellik adları yapılandırma kaynağında anahtar adı olarak kullanılır. Özellik adı ise Title, yapılandırmadaki anahtar adı da öyledir Title .

Adlar farklılaştığında, yapılandırma kaynağında [ConfigurationKeyName] anahtar adını belirtmek için özniteliği kullanabilirsiniz. Bu tekniği kullanarak, yapılandırmadaki bir özelliği kodunuzdaki farklı bir ada sahip bir özelliğe eşleyebilirsiniz. Bu, yapılandırma kaynağındaki özellik adı geçerli bir C# tanımlayıcısı olmadığında veya kodunuzda farklı bir ad kullanmak istediğinizde kullanışlıdır.

Örneğin, aşağıdaki seçenekler sınıfını göz önünde bulundurun.

PositionKeyName.cs:

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

    [ConfigurationKeyName("PositionName")]
    public string? Name { get; set; }

    [ConfigurationKeyName("PositionTitle")]
    public string? Title { get; set; }
}

Name ve Title sınıf özellikleri, aşağıdaki JSON yapılandırmasından PositionName ve PositionTitle ile ilişkilidir:

"PositionKeyName": {
  "PositionName": "Carlos Diego",
  "PositionTitle": "Director"
}

PositionKeyNameOptions.razor:

@page "/position-key-name-options"
@inject IConfiguration Config

Name: @positionOptions?.Name<br>
Title: @positionOptions?.Title

@code {
    private PositionKeyName? positionOptions;

    protected override void OnInitialized() =>
        positionOptions = Config.GetSection(PositionKeyName.Position)
            .Get<PositionKeyName>();
}

PositionKeyName.cshtml:

@page
@model RazorPagesSample.Pages.PositionKeyNameModel
@{
}

PositionKeyName.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPagesSample.Pages;

public class PositionKeyNameModel : PageModel
{
    private readonly IConfiguration _config;

    public PositionKeyNameModel(IConfiguration config)
    {
        _config = config;
    }

    public ContentResult OnGet()
    {
        var positionOptions = _config.GetSection(PositionKeyName.Position)
            .Get<PositionKeyName>();

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

Çıktı:

Name: Carlos Diego
Title: Director

Uygulama başlatıldıktan sonra, uygulama ayarları dosyasındaki JSON yapılandırmasında yapılan değişiklikler okunur. Davranışı göstermek için, uygulama ayarları dosyasındaki bir veya her iki yapılandırma değerini değiştirin ve uygulamayı yeniden başlatmadan sayfayı yeniden yükleyin.

Adlandırılmış seçenekleri IConfigureNamedOptions kullanarak destekleyin.

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 JSON yapılandırmasını göz önünde bulundurun:

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

İki sınıf yerine TopItem:Month ve TopItem:Year bağlamak için, her bölüm için aşağıdaki sınıf kullanılır.

TopItemSettings.cs:

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

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

Hizmetlerin bağımlılık ekleme için kaydedildiği durumlarda, aşağıdaki örnekte adlandırılmış seçenekler yapılandırılır:

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

Aşağıdaki örnekte adlandırılmış seçenekler görüntülenir:

NamedOptions.razor:

@page "/named-options"
@using Microsoft.Extensions.Options
@inject IOptionsSnapshot<TopItemSettings> Options

Month: Name: @monthTopItem?.Name Model: @monthTopItem?.Model<br>
Year: Name: @yearTopItem?.Name Model: @yearTopItem?.Model

@code {
    private TopItemSettings? monthTopItem;
    private TopItemSettings? yearTopItem;

    protected override void OnInitialized()
    {
        monthTopItem = Options.Get(TopItemSettings.Month);
        yearTopItem = Options.Get(TopItemSettings.Year);
    }
}

NamedOptions.cshtml:

@page
@model RazorPagesSample.Pages.NamedOptionsModel
@{
}

NamedOptions.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class NamedOptionsModel : PageModel
{
    private readonly IOptionsSnapshot<TopItemSettings> _options;

    public NamedOptionsModel(IOptionsSnapshot<TopItemSettings> options)
    {
        _options = options;
    }

    public ContentResult OnGet()
    {
        var monthTopItem = _options.Get(TopItemSettings.Month);
        var yearTopItem = _options.Get(TopItemSettings.Year);

        return Content(
            $"Month:Name {monthTopItem.Name}\n" +
            $"Month:Model {monthTopItem.Model}\n" +
            $"Year:Name {yearTopItem.Name}\n" +
            $"Year:Model {yearTopItem.Model}");
    }
}

Tüm seçenekler adlandırılmış örneklerdir. IConfigureOptions<TOptions> örnekleri, Options.DefaultName örneğini hedef alacak şekilde değerlendirilir ve bu örnek string.Empty'dir. IConfigureNamedOptions<TOptions> ayrıca uygular IConfigureOptions<TOptions>. Varsayılan uygulamanın IOptionsFactory<TOptions> her birini uygun şekilde kullanma mantığına sahiptir. 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.

Yapılandırma sonrası seçeneklerle ilgili yönergeler, Seçenekler Sonrası Yapılandırma bölümünde sağlanır.

OptionsBuilder API

OptionsBuilder<TOptions> TOptions örneklerini yapılandırmak 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çenekler doğrulaması ve hizmet bağımlılıklarını kabul eden aşırı yüklemeler, yalnızca IConfigureOptions<TOptions> aracılığıyla kullanılabilir (bkz. OptionsBuilder).

OptionsBuilder<TOptions> , Seçenekler doğrulama bölümünde gösterilmiştir.

Özel depo ekleme hakkında bilgi için bkz. ASP.NET Core'da Veri Koruma API'lerini kullanmaya başlama.

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:

Yapılandırma temsilcisi yaklaşımı

Hizmetlerin bağımlılık ekleme için kaydedildiği durumlarda, Configure üzerindeki OptionsBuilder<TOptions> için 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<PositionOptions>("optionalName")
    .Configure<Service1, Service2, Service3, Service4, Service5>(
        (o, s, s2, s3, s4, s5) => 
            o.Property = DoSomethingWith(s, s2, s3, s4, s5));
services.AddOptions<PositionOptions>("optionalName")
    .Configure<Service1, Service2, Service3, Service4, Service5>(
        (o, s, s2, s3, s4, s5) => 
            o.Property = DoSomethingWith(s, s2, s3, s4, s5));

Yapılandırma seçenekleri hizmet yaklaşımı

IConfigureOptions<TOptions> veya IConfigureNamedOptions<TOptions> uygulayan bir tür oluşturun ve bu türü bir hizmet olarak kaydedin.

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

Seçenekler doğrulaması

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

Aşağıdaki JSON yapılandırmasını göz önünde bulundurun:

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

Aşağıdaki sınıf, "KeyOptions" yapılandırma bölümüne bağlanmak için kullanılır ve normal ifade ile aralık gereksinimini içeren iki veri ek açıklamaları kuralı uygular.

KeyOptions.cs:

public class KeyOptions
{
    public const string Key = "KeyOptions";

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

Bağımlılık ekleme için hizmetlerin kaydedildiği yer, aşağıdaki örnek:

builder.Services.AddOptions<KeyOptions>()
    .Bind(builder.Configuration.GetSection(KeyOptions.Key))
    .ValidateDataAnnotations();
services.AddOptions<KeyOptions>()
    .Bind(builder.Configuration.GetSection(KeyOptions.Key))
    .ValidateDataAnnotations();

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

Hizmetlerin bağımlılık ekleme için kaydedildiği durumlarda, aşağıdaki örnek bir temsilci kullanarak daha karmaşık bir doğrulama kuralı uygular:

builder.Services.AddOptions<KeyOptions>()
        .Bind(builder.Configuration.GetSection(KeyOptions.Key))
        .ValidateDataAnnotations()
    .Validate(options =>
    {
        return options.Key3 > options.Key2;
    }, "Key3 must be > than Key2");
services.AddOptions<KeyOptions>()
        .Bind(builder.Configuration.GetSection(KeyOptions.Key))
        .ValidateDataAnnotations()
    .Validate(options =>
    {
        return options.Key3 > options.Key2;
    }, "Key3 must be > than Key2");

Aşağıdaki örnekte, seçenekleri doğrulama özel durumlarını günlüğe kaydetme ve görüntüleme OptionsValidationException.Message işlemleri gösterilmektedir.

Note

Tanıtım amacıyla, aşağıdaki örnekte ham HTML biçimlendirmek için bir MarkupString kullanılır. Güvenilmeyen bir kaynaktan oluşturulan ham HTML'nin işlenmesi bir güvenlik riskidir ve her zaman bundan kaçınılmalıdır. Daha fazla bilgi için ASP.NET Core Razor bileşenleri bölümüne bakın.

OptionsValidation1.razor:

@page "/options-validation-1"
@inject IOptionsSnapshot<KeyOptions> Options
@inject ILogger<OptionsValidation1> Logger

@if (message is not null)
{
    @((MarkupString)message)
}

@code {
    private string? message;

    protected override void OnInitialized()
    {
        try
        {
            var keyOptions = Options.Value;
        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                Logger.LogError(failure);
            }
        }

        try
        {
            message = 
                $"Key1: {Options.Value.Key1}<br>" +
                $"Key2: {Options.Value.Key2}<br>" +
                $"Key3: {Options.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            message = optValEx.Message;
        }
    }
}

Aşağıdaki örnek, sayfa modelinin oluşturucusunda, seçenekler doğrulama özel durumlarının nasıl günlüğe kaydedileceğini ve sayfanın OptionsValidationException.Message yönteminde bir OnGet'ün nasıl görüntüleneceğini göstermektedir.

OptionsValidation1.cshtml:

@page
@model RazorPagesSample.Pages.OptionsValidation1Model
@{
}

OptionsValidation1.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class OptionsValidation1Model : PageModel
{
    private readonly IOptionsSnapshot<KeyOptions>? _options;

    public OptionsValidation1Model(IOptionsSnapshot<KeyOptions> options,
        ILogger<OptionsValidation1Model> logger)
    {
        _options = options;

        try
        {
            var keyOptions = _options?.Value;
        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                logger?.LogError("Validation: {Failure}", failure);
            }
        }
    }

    public ContentResult OnGet()
    {
        string message;

        try
        {
            message =
                $"Key1: {_options?.Value.Key1}\n" +
                $"Key2: {_options?.Value.Key2}\n" +
                $"Key3: {_options?.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }

        return Content(message);
    }
}

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

  • Doğrulama hatası göstermemek için yukarıdaki uygulama ayarları yapılandırmasıyla kodu kullanın.
  • Uygulama ayarları dosyasındaki yapılandırmayı, veri ek açıklama kurallarını ihlal eden bir veya daha fazla yolla değiştirin. Kural ihlallerini görmek için seçenekler doğrulama sayfasını yeniden yükleyin.

Aşağıdaki örnekte, uygulama ayarları dosyasındaki Key2 değeri sıfırın altında veya 1.000'in üzerinde bir değere değiştirilirse, sayfa içeriği Key2 değerinin aralığın dışında olduğunu gösterir.

DataAnnotation validation failed for 'KeyOptions' members: 'Key2' with the error: 'Value for Key2 must be between 0 and 1000.'.

Ayrılmış bir sınıfta IValidateOptions<TOptions> ile seçenekleri doğrulayın.

Seçenekleri, veri ek açıklamaları veya uygulamanın IValidateOptions<TOptions> dosyasındaki doğrulama kurallarını korumaya gerek kalmadan, Program uygulayarak doğrulayın.

Aşağıdaki örnekte, önceki örneklerdeki veri açıklama kuralları ve seçeneklerin doğrulaması bir doğrulama sınıfına devredilir. Options model sınıfı (KeyOptions2), veri ek açıklamaları içermez.

Aşağıdaki JSON yapılandırmasını göz önünde bulundurun:

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

KeyOptions2.cs:

public class KeyOptions2
{
    public const string Key = "KeyOptions";

    public string? Key1 { get; set; }
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}
public class KeyOptionsValidation : IValidateOptions<KeyOptions2>
{
    public ValidateOptionsResult Validate(string? name, KeyOptions2 options)
    {
        if (options == null)
        {
            return ValidateOptionsResult.Fail("KeyOptions not found.");
        }

        StringBuilder? validationResult = new();
        var rx = new Regex(@"^[a-zA-Z\s]{1,40}$");
        var match = rx.Match(options.Key1!);

        if (string.IsNullOrEmpty(match.Value))
        {
            validationResult.Append($"{options.Key1} doesn't match RegEx<br>");
        }

        if (options.Key2 < 0 || options.Key2 > 1000)
        {
            validationResult.Append($"{options.Key2} doesn't match Range 0 - 1000<br>");
        }

        if (options.Key3 < options.Key2)
        {
            validationResult.Append("Key3 must be > than Key2<br>");
        }

        if (validationResult.Length > 0)
        {
            return ValidateOptionsResult.Fail(validationResult.ToString());
        }

        return ValidateOptionsResult.Success;
    }
}
public class KeyOptionsValidation : IValidateOptions<KeyOptions2>
{
    public ValidateOptionsResult Validate(string? name, KeyOptions2 options)
    {
        if (options == null)
        {
            return ValidateOptionsResult.Fail("KeyOptions not found");
        }

        StringBuilder? validationResult = new();
        var rx = new Regex(@"^[a-zA-Z\s]{1,40}$");
        var match = rx.Match(options.Key1!);

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

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

        if (options.Key3 < options.Key2)
        {
            validationResult.Append("Key3 must be > than Key2\n");
        }

        if (validationResult.Length > 0)
        {
            return ValidateOptionsResult.Fail(validationResult.ToString());
        }

        return ValidateOptionsResult.Success;
    }
}

Hizmetlerin bağımlılık ekleme için kaydedildiği ve önceki kodun kullanıldığı durumlarda aşağıdaki örnekte doğrulama etkinleştirilir Program.cs :

builder.Services.Configure<KeyOptions2>(
    builder.Configuration.GetSection(KeyOptions2.Key));

builder.Services.AddSingleton<IValidateOptions<KeyOptions2>, 
    KeyOptionsValidation>();
services.Configure<KeyOptions>(
    builder.Configuration.GetSection(KeyOptions2.Key));

services.AddSingleton<IValidateOptions<KeyOptions2>, KeyOptionsValidation>();

Aşağıdaki örnekte, seçenekleri doğrulama özel durumlarını günlüğe kaydetme ve görüntüleme OptionsValidationException.Message işlemleri gösterilmektedir.

OptionsValidation2.razor:

@page "/options-validation-2"
@inject IOptionsSnapshot<KeyOptions2> Options
@inject ILogger<OptionsValidation2> Logger

@if (message is not null)
{
    @((MarkupString)message)
}

@code {
    private string? message;

    protected override void OnInitialized()
    {
        try
        {
            var keyOptions = Options.Value;
        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                Logger.LogError(failure);
            }
        }

        try
        {
            message = 
                $"Key1: {Options.Value.Key1}<br>" +
                $"Key2: {Options.Value.Key2}<br>" +
                $"Key3: {Options.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            message = optValEx.Message;
        }
    }
}

Aşağıdaki örnek, sayfa modelinin oluşturucusunda, seçenekler doğrulama özel durumlarının nasıl günlüğe kaydedileceğini ve sayfanın OptionsValidationException.Message yönteminde bir OnGet'ün nasıl görüntüleneceğini göstermektedir.

OptionsValidation2.cshtml:

@page
@model RazorPagesSample.Pages.OptionsValidation2Model
@{
}

OptionsValidation2.cshtml.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Options;

namespace RazorPagesSample.Pages;

public class OptionsValidation2Model : PageModel
{
    private readonly IOptionsSnapshot<KeyOptions2>? _options;

    public OptionsValidation2Model(IOptionsSnapshot<KeyOptions2> options,
        ILogger<OptionsValidation2Model> logger)
    {
        _options = options;

        try
        {
            var keyOptions = _options?.Value;
        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                logger?.LogError("Validation: {Failure}", failure);
            }
        }
    }

    public ContentResult OnGet()
    {
        string message;

        try
        {
            message =
                $"Key1: {_options?.Value.Key1}\n" +
                $"Key2: {_options?.Value.Key2}\n" +
                $"Key3: {_options?.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }

        return Content(message);
    }
}

"IValidatableObject ile sınıf seviyesinde doğrulama"

Seçenekler doğrulaması, sınıfın içindeki bir sınıfın sınıf düzeyi doğrulamasını gerçekleştirmeyi destekler IValidatableObject :

Uygulama ile başladığında seçenek doğrulamasını çalıştır ValidateOnStart

Seçenek doğrulama, bir TOption örneği ilk kez oluşturulduğunda çalışır; bu, bir istek işlem hattında ilk kez IOptionsSnapshot<TOptions>.Value'e erişildiğinde veya IOptionsMonitor<TOptions>.Get(string) çağrıldığında gerçekleşir. Seçenekler her yeniden yüklendiğinde doğrulama yeniden çalıştırılır.

Uygulama başlatıldığında seçenekler doğrulamasını çalıştırmak için, bağımlılık enjeksiyonu için hizmetlerin kaydedildiği ValidateOnStart dosyasında Program metodunu çağırın:

builder.Services.AddOptions<KeyOptions>()
    .Bind(builder.Configuration.GetSection(KeyOptions.Key))
    .ValidateDataAnnotations()
    .ValidateOnStart();

Yapılandırma sonrası seçenekler

Hizmetlerin bağımlılık ekleme için kaydedildiği durumlarda, PostConfigure belirli bir adlandırılmış seçeneği başlatmak için kullanılabilir. Aşağıdaki örnekte, yalnızca TopItem:Month:Name sonradan yapılandırılmıştır.

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>(TopItemSettings.Month, options =>
{
    options.Name = "Blue Gizmo";
});
services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

services.PostConfigure<TopItemSettings>(TopItemSettings.Month, options =>
{
    options.Name = "Blue Gizmo";
});

, yalnızca TopItem:Month:Name öğesi yapılandırıldığında oluşturulan çıkış:

Month: Name: Blue Gizmo Model: GW46
Year: Name: Orange Gadget Model: OG35

Hizmetlerin bağımlılık ekleme için kaydedildiği durumlarda, belirtilen seçenek türünün tüm adlandırılmış örneklerini başlatmak için kullanın PostConfigureAll . Aşağıdaki örnekte, tüm TopItem.Name örnekleri Blue Gizmo olarak ayarlanmıştır.

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

builder.Services.PostConfigureAll<TopItemSettings>(options =>
{
    options.Name = "Blue Gizmo";
});
services.Configure<TopItemSettings>(TopItemSettings.Month,
    builder.Configuration.GetSection("TopItem:Month"));
services.Configure<TopItemSettings>(TopItemSettings.Year,
    builder.Configuration.GetSection("TopItem:Year"));

services.PostConfigureAll<TopItemSettings>(options =>
{
    options.Name = "Blue Gizmo";
});

Adlandırılmış seçenekler örneği, burada tüm TopItem:Name seçenekler yapılandırıldıktan sonra oluşturulan çıktı:

Month: Name: Blue Gizmo Model: GW46
Year: Name: Blue Gizmo Model: OG35

İstek işleme işlem hattındaki erişim seçenekleri

İstek işleme işlem hattında IOptions<TOptions> veya IOptionsMonitor<TOptions> erişmek için GetRequiredService üzerinde WebApplication.Services çağrısı yapabilirsiniz.

var name = app.Services.GetRequiredService<IOptionsMonitor<PositionOptions>>()
    .CurrentValue.Name;

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

Aşağıdaki örnekte, IOptionsMonitor<TOptions> değerlerini elde etmek için Startup.Configure yöntemine PositionOptions enjekte edilir.

public void Configure(IApplicationBuilder app, 
    IOptionsMonitor<PositionOptions> options)

İstek işleme işlem hattındaki seçeneklere Startup.Configure ile erişin.

var name = options.CurrentValue.Name;

IOptions<TOptions> veya IOptionsMonitor<TOptions>, Startup.ConfigureServices içinde kullanmayın. Hizmet kayıtlarının sıralanması nedeniyle seçenek durumunda tutarsızlık oluşabilir.

Ek kaynaklar