ASP.NET Core 中的選項模式Options pattern in ASP.NET Core

Kirk LarkinRick AndersonBy Kirk Larkin and Rick Anderson.

選項模式使用類別來提供相關設定群組的強型別存取。The options pattern uses classes to provide strongly typed access to groups of related settings. 組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

選項也提供驗證設定資料的機制。Options also provide a mechanism to validate configuration data. 如需詳細資訊,請參閱選項驗證一節。For more information, see the Options validation section.

本主題提供 ASP.NET Core 中選項模式的相關資訊。This topic provides information on the options pattern in ASP.NET Core. 如需在主控台應用程式中使用選項模式的詳細資訊,請參閱 .net 中的選項模式For information on using the options pattern in console apps, see Options pattern in .NET.

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

系結階層式設定Bind hierarchical configuration

讀取相關設定值的慣用方式是使用 選項模式The preferred way to read related configuration values is using the options pattern. 例如,若要讀取下列設定值:For example, to read the following configuration values:

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

建立下列 PositionOptions 類別:Create the following PositionOptions class:

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

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

Options 類別:An options class:

  • 必須是具有公用無參數的函式的非抽象。Must be non-abstract with a public parameterless constructor.
  • 型別的所有公用讀寫屬性都會系結。All public read-write properties of the type are bound.
  • 欄位為 *not _ 系結。Fields are *not _ bound. 在上述程式碼中,未系結 PositionIn the preceding code, Position is not bound. 使用屬性,因此在將類別系結 Position "Position" 至設定提供者時,不需要在應用程式中硬式編碼字串。The Position property is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.

下列程式碼:The following code:

_ 呼叫 ConfigurationBinder ,將類別系結至 PositionOptions Position 區段。_ Calls ConfigurationBinder.Bind to bind the PositionOptions class to the Position section.

  • 顯示 Position 設置資料。Displays the Position configuration data.
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}");
    }
}

在上述程式碼中,預設會讀取應用程式啟動後的 JSON 設定檔變更。In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

ConfigurationBinder.Get<T> 系結並傳回指定的型別。ConfigurationBinder.Get<T> binds and returns the specified type. ConfigurationBinder.Get<T> 可能比使用更方便 ConfigurationBinder.BindConfigurationBinder.Get<T> may be more convenient than using ConfigurationBinder.Bind. 下列程式碼顯示如何搭配 ConfigurationBinder.Get<T> PositionOptions 類別使用:The following code shows how to use ConfigurationBinder.Get<T> with the PositionOptions class:

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}");
    }
}

在上述程式碼中,預設會讀取應用程式啟動後的 JSON 設定檔變更。In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

使用 *選項模式 _ 的替代方法是系結 Position 區段,並將它加入至相依性 插入服務容器An alternative approach when using the *options pattern _ is to bind the Position section and add it to the dependency injection service container. 在下列程式碼中, PositionOptions 會新增至服務容器, <xref:Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure_> 並系結至設定:In the following code, PositionOptions is added to the service container with <xref:Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure_> and bound to configuration:

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

使用上述程式碼,下列程式碼會讀取位置選項:Using the preceding code, the following code reads the position options:

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}");
    }
}

在上述程式碼中, 會讀取應用程式啟動後的 JSON 設定檔變更。In the preceding code, changes to the JSON configuration file after the app has started are not read. 若要讀取應用程式啟動後的變更,請使用 IOptionsSnapshotTo read changes after the app has started, use IOptionsSnapshot.

選項介面Options interfaces

IOptions<TOptions>:IOptions<TOptions>:

IOptionsSnapshot<TOptions>:IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:IOptionsMonitor<TOptions>:

設定案例會在進行所有設定之後,啟用設定或變更選項 IConfigureOptions<TOptions>Post-configuration scenarios enable setting or changing options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> 負責建立新的選項執行個體。IOptionsFactory<TOptions> is responsible for creating new options instances. 它有單一 Create 方法。It has a single Create method. 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). 值可以使用 TryAdd 手動導入。Values can be manually introduced with TryAdd. Clear 方法用於應該視需要重新建立所有具名執行個體時。The Clear method is used when all named instances should be recreated on demand.

使用 IOptionsSnapshot 讀取更新的資料Use IOptionsSnapshot to read updated data

使用 IOptionsSnapshot<TOptions> ,在要求的存留期記憶體取和快取選項時,會針對每個要求計算一次。Using IOptionsSnapshot<TOptions>, options are computed once per request when accessed and cached for the lifetime of the request. 使用支援讀取已更新設定值的設定提供者時,會在應用程式啟動後讀取設定的變更。Changes to the configuration are read after the app starts when using configuration providers that support reading updated configuration values.

和之間的差異在於 IOptionsMonitor IOptionsSnapshotThe difference between IOptionsMonitor and IOptionsSnapshot is that:

  • IOptionsMonitor單一服務 ,可隨時抓取目前的選項值,這在單一相依性中特別有用。IOptionsMonitor is a singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies.
  • IOptionsSnapshot 是限 域的服務 ,會在建立物件時提供選項的快照 IOptionsSnapshot<T>IOptionsSnapshot is a scoped service and provides a snapshot of the options at the time the IOptionsSnapshot<T> object is constructed. 選項快照集的設計目的是要搭配使用暫時性和限定範圍的相依性。Options snapshots are designed for use with transient and scoped dependencies.

下列程式碼使用 IOptionsSnapshot<TOptions>The following code uses 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}");
    }
}

下列程式碼會註冊系結的設定實例 MyOptionsThe following code registers a configuration instance which MyOptions binds against:

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

    services.AddRazorPages();
}

在上述程式碼中,會讀取應用程式啟動後的 JSON 設定檔變更。In the preceding code, changes to the JSON configuration file after the app has started are read.

IOptionsMonitorIOptionsMonitor

下列程式碼會註冊針對系結的設定實例 MyOptionsThe following code registers a configuration instance which MyOptions binds against.

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

    services.AddRazorPages();
}

下列範例會使用 IOptionsMonitor<TOptions>The following example uses 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}");
    }
}

在上述程式碼中,預設會讀取應用程式啟動後的 JSON 設定檔變更。In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

使用 IConfigureNamedOptions 的命名選項支援Named options support using IConfigureNamedOptions

命名選項:Named options:

  • 當多個設定區段系結至相同的屬性時,會很有用。Are useful when multiple configuration sections bind to the same properties.
  • 會區分大小寫。Are case sensitive.

請考慮下列檔案 appsettings.jsonConsider the following appsettings.json file:

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

TopItem:Month TopItem:Year 下列類別可用於每個區段,而不是建立兩個類別來系結和:Rather than creating two classes to bind TopItem:Month and TopItem:Year, the following class is used for each section:

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

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

下列程式碼會設定命名選項:The following code configures the named options:

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();
}

下列程式碼會顯示已命名的選項:The following code displays the named options:

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"   );
    }
}

所有選項都是具名執行個體。All options are named instances. IConfigureOptions<TOptions> 系統會將實例視為目標 Options.DefaultName 實例,也就是 string.EmptyIConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. null 命名選項用來以所有已命名的實例為目標,而不是特定的已命名實例。The null named option is used to target all of the named instances instead of a specific named instance. ConfigureAllPostConfigureAll 使用此慣例。ConfigureAll and PostConfigureAll use this convention.

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。OptionsBuilder<TOptions> is used to configure TOptions instances. 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

OptionsBuilder 在 [ 選項驗證 ] 區段中使用。OptionsBuilder is used in the Options validation section.

使用 DI 服務來設定選項Use DI services to configure options

您可以透過下列兩種方式,從相依性插入來存取服務:Services can be accessed from dependency injection while configuring options in two ways:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。We recommend passing a configuration delegate to Configure, since creating a service is more complex. 建立類型相當於呼叫 設定時的架構。Creating a type is equivalent to what the framework does when calling Configure. 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

選項驗證Options validation

選項驗證可讓您驗證選項值。Options validation enables option values to be validated.

請考慮下列檔案 appsettings.jsonConsider the following appsettings.json file:

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

下列類別會系結至設定 "MyConfig" 區段,並套用一些 DataAnnotations 規則:The following class binds to the "MyConfig" configuration section and applies a couple of DataAnnotations rules:

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

下列程式碼:The following code:

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擴充方法定義于DataAnnotations NuGet 套件中。The ValidateDataAnnotations extension method is defined in the Microsoft.Extensions.Options.DataAnnotations NuGet package. 針對使用 SDK 的 web 應用程式 Microsoft.NET.Sdk.Web ,會從共用架構隱含參考此套件。For web apps that use the Microsoft.NET.Sdk.Web SDK, this package is referenced implicitly from the shared framework.

下列程式碼顯示設定值或驗證錯誤:The following code displays the configuration values or the validation errors:

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

下列程式碼會使用委派來套用更複雜的驗證規則:The following code applies a more complex validation rule using a delegate:

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();
}

複雜驗證的 IValidateOptionsIValidateOptions for complex validation

下列類別會實行 IValidateOptions<TOptions>The following class implements 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 可將驗證程式代碼從和移出 StartUp 至類別。IValidateOptions enables moving the validation code out of StartUp and into a class.

使用上述程式碼,即可在中使用下列程式碼來啟用驗證 Startup.ConfigureServicesUsing the preceding code, validation is enabled in Startup.ConfigureServices with the following code:

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

選項設定後作業Options post-configuration

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。Set post-configuration with IPostConfigureOptions<TOptions>. 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

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

PostConfigure 可用來後置設定具名選項:PostConfigure is available to post-configure named options:

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

使用 PostConfigureAll 後置設定所有設定執行個體:Use PostConfigureAll to post-configure all configuration instances:

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

在啟動期間存取選項Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. 可能會因為服務註冊的順序而有不一致的選項狀態存在。An inconsistent options state may exist due to the ordering of service registrations.

Options.ConfigurationExtensions NuGet 套件Options.ConfigurationExtensions NuGet package

ASP.NET Core 應用程式中會隱含參考 Microsoft.Extensions.Options.ConfigurationExtensions 套件。The Microsoft.Extensions.Options.ConfigurationExtensions package is implicitly referenced in ASP.NET Core apps.

選項模式使用類別來代表一組相關的設定。The options pattern uses classes to represent groups of related settings. 組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

選項也提供驗證設定資料的機制。Options also provide a mechanism to validate configuration data. 如需詳細資訊,請參閱選項驗證一節。For more information, see the Options validation section.

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

先決條件Prerequisites

參考 Microsoft.AspNetCore.App 中繼套件,或新增 Microsoft.Extensions.Options.ConfigurationExtensions 套件的套件參考。Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Options.ConfigurationExtensions package.

選項介面Options interfaces

IOptionsMonitor<TOptions> 是用來擷取選項並管理 TOptions 執行個體的選項通知。IOptionsMonitor<TOptions> is used to retrieve options and manage options notifications for TOptions instances. IOptionsMonitor<TOptions> 支援以下案例:IOptionsMonitor<TOptions> supports the following scenarios:

設定後案例可讓您在所有 IConfigureOptions<TOptions> 設定發生時設定或變更選項。Post-configuration scenarios allow you to set or change options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> 負責建立新的選項執行個體。IOptionsFactory<TOptions> is responsible for creating new options instances. 它有單一 Create 方法。It has a single Create method. 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). 值可以使用 TryAdd 手動導入。Values can be manually introduced with TryAdd. Clear 方法用於應該視需要重新建立所有具名執行個體時。The Clear method is used when all named instances should be recreated on demand.

IOptionsSnapshot<TOptions> 在應該於收到每個要求時重新計算選項的案例中很實用用。IOptionsSnapshot<TOptions> is useful in scenarios where options should be recomputed on every request. 如需詳細資訊,請參閱使用 IOptionsSnapshot 重新載入設定資料一節。For more information, see the Reload configuration data with IOptionsSnapshot section.

IOptions<TOptions> 可用於支援選項。IOptions<TOptions> can be used to support options. 不過,IOptions<TOptions> 不支援前面的 IOptionsMonitor<TOptions> 案例。However, IOptions<TOptions> doesn't support the preceding scenarios of IOptionsMonitor<TOptions>. 您可以在現有架構與程式庫中繼續使用 IOptions<TOptions>,此程式庫已使用 IOptions<TOptions> 介面且不需要 IOptionsMonitor<TOptions> 提供的案例。You may continue to use IOptions<TOptions> in existing frameworks and libraries that already use the IOptions<TOptions> interface and don't require the scenarios provided by IOptionsMonitor<TOptions>.

一般選項設定General options configuration

一般選項設定是以範例應用程式中的範例 1 來示範。General options configuration is demonstrated as Example 1 in the sample app.

選項類別必須為非抽象,且具有公用的無參數建構函式。An options class must be non-abstract with a public parameterless constructor. 下列 MyOptions 類別有兩個屬性,Option1Option2The following class, MyOptions, has two properties, Option1 and Option2. 設定預設值為選擇性,但在下列範例中,類別建構函式會設定 Option1 的預設值。Setting default values is optional, but the class constructor in the following example sets the default value of Option1. Option2 的預設值直接藉由初始化屬性來設定 (Models/MyOptions.cs):Option2 has a default value set by initializing the property directly (Models/MyOptions.cs):

public class MyOptions
{
    public MyOptions()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

MyOptions 類別使用 Configure 新增到服務容器,並繫結到設定:The MyOptions class is added to the service container with Configure and bound to configuration:

// Example #1: General configuration
// Register the Configuration instance which MyOptions binds against.
services.Configure<MyOptions>(Configuration);

下列頁面模型使用 建構函式相依性插入搭配 IOptionsMonitor<TOptions> 來存取設定 (Pages/Index.cshtml.cs):The following page model uses constructor dependency injection with IOptionsMonitor<TOptions> to access the settings (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #1: Simple options
var option1 = _options.Option1;
var option2 = _options.Option2;
SimpleOptions = $"option1 = {option1}, option2 = {option2}";

範例的檔案會 appsettings.json 指定和的 option1option2The sample's appsettings.json file specifies values for option1 and option2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:When the app is run, the page model's OnGet method returns a string showing the option class values:

option1 = value1_from_json, option2 = -1

注意

使用自訂 ConfigurationBuilder 從設定檔載入選項設定時,請確認已正確設定基底路徑:When using a custom ConfigurationBuilder to load options configuration from a settings file, confirm that the base path is set correctly:

var configBuilder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: true);
var config = configBuilder.Build();

services.Configure<MyOptions>(config);

透過 CreateDefaultBuilder 從設定檔載入選項設定時,不需要明確設定基底路徑。Explicitly setting the base path isn't required when loading options configuration from the settings file via CreateDefaultBuilder.

使用委派設定簡單的選項Configure simple options with a delegate

使用委派設定簡單的選項是以範例應用程式中的範例 2 來示範。Configuring simple options with a delegate is demonstrated as Example 2 in the sample app.

使用委派來設定選項值。Use a delegate to set options values. 範例應用程式使用 MyOptionsWithDelegateConfig 類別 (Models/MyOptionsWithDelegateConfig.cs):The sample app uses the MyOptionsWithDelegateConfig class (Models/MyOptionsWithDelegateConfig.cs):

public class MyOptionsWithDelegateConfig
{
    public MyOptionsWithDelegateConfig()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

在下列程式碼中,第二個 IConfigureOptions<TOptions> 服務新增至服務容器。In the following code, a second IConfigureOptions<TOptions> service is added to the service container. 它使用委派,以 MyOptionsWithDelegateConfig 設定繫結:It uses a delegate to configure the binding with MyOptionsWithDelegateConfig:

// Example #2: Options bound and configured by a delegate
services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
{
    myOptions.Option1 = "value1_configured_by_delegate";
    myOptions.Option2 = 500;
});

Index.cshtml.csIndex.cshtml.cs:

private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #2: Options configured by delegate
var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
SimpleOptionsWithDelegateConfig = 
    $"delegate_option1 = {delegate_config_option1}, " +
    $"delegate_option2 = {delegate_config_option2}";

您可以新增多個設定提供者。You can add multiple configuration providers. 設定提供者可在 NuGet 套件中找到,而且會依註冊順序套用。Configuration providers are available from NuGet packages and are applied in the order that they're registered. 如需詳細資訊,請參閱 ASP.NET Core 的設定For more information, see ASP.NET Core 的設定.

每次呼叫 Configure 時都會新增 IConfigureOptions<TOptions> 服務到服務容器。Each call to Configure adds an IConfigureOptions<TOptions> service to the service container. 在上述範例中,和的值 Option1Option2 是指定于中 appsettings.json ,但是和的值 Option1 Option2 會由設定的委派覆寫。In the preceding example, the values of Option1 and Option2 are both specified in appsettings.json, but the values of Option1 and Option2 are overridden by the configured delegate.

啟用多個設定服務時,最後一個指定的設定來源會「勝出」並設定此組態值。When more than one configuration service is enabled, the last configuration source specified wins and sets the configuration value. 當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:When the app is run, the page model's OnGet method returns a string showing the option class values:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子選項組態Suboptions configuration

子選項組態是以範例應用程式中的範例 3 來示範。Suboptions configuration is demonstrated as Example 3 in the sample app.

應用程式應該建立屬於應用程式中特定案例群組 (類別) 的選項類別。Apps should create options classes that pertain to specific scenario groups (classes) in the app. 需要組態值的應用程式組件應該只能存取它們使用的設定值。Parts of the app that require configuration values should only have access to the configuration values that they use.

將選項繫結至組態時,選項類型中的每一個屬性都會繫結至 property[:sub-property:] 格式的組態索引鍵。When binding options to configuration, each property in the options type is bound to a configuration key of the form property[:sub-property:]. 例如, MyOptions.Option1 屬性會系結至索引鍵,這個索引鍵 Option1 是從的 option1 屬性中讀取的 appsettings.jsonFor example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json.

在下列程式碼中,第三個 IConfigureOptions<TOptions> 服務新增至服務容器。In the following code, a third IConfigureOptions<TOptions> service is added to the service container. 它會系結至檔案的 MySubOptions 區段 subsection appsettings.jsonIt binds MySubOptions to the section subsection of the appsettings.json file:

// Example #3: Suboptions
// Bind options using a sub-section of the appsettings.json file.
services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

GetSection方法需要 Microsoft.Extensions.Configuration 命名空間。The GetSection method requires the Microsoft.Extensions.Configuration namespace.

範例的檔案會 appsettings.json 定義 subsection 具有和之索引鍵的成員 suboption1 suboption2The sample's appsettings.json file defines a subsection member with keys for suboption1 and suboption2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

MySubOptions 類別會定義屬性 SubOption1SubOption2,來保存選項值 (Models/MySubOptions.cs):The MySubOptions class defines properties, SubOption1 and SubOption2, to hold the options values (Models/MySubOptions.cs):

public class MySubOptions
{
    public MySubOptions()
    {
        // Set default values.
        SubOption1 = "value1_from_ctor";
        SubOption2 = 5;
    }
    
    public string SubOption1 { get; set; }
    public int SubOption2 { get; set; }
}

頁面模型的 OnGet 方法會傳回具有選項值 (Pages/Index.cshtml.cs) 的字串:The page model's OnGet method returns a string with the options values (Pages/Index.cshtml.cs):

private readonly MySubOptions _subOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #3: Suboptions
var subOption1 = _subOptions.SubOption1;
var subOption2 = _subOptions.SubOption2;
SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

當應用程式執行時,OnGet 方法會傳回字串,顯示子選項類別值:When the app is run, the OnGet method returns a string showing the suboption class values:

subOption1 = subvalue1_from_json, subOption2 = 200

選項插入Options injection

選項插入在範例應用程式中會示範為範例4。Options injection is demonstrated as Example 4 in the sample app.

插入 IOptionsMonitor<TOptions>Inject IOptionsMonitor<TOptions> into:

  • 具有指示詞的 Razor 頁面或 MVC 視圖 @inject Razor 。A Razor page or MVC view with the @inject Razor directive.
  • 頁面或視圖模型。A page or view model.

範例應用程式中的下列範例會插入 IOptionsMonitor<TOptions> 頁面模型中, (Pages/Index. cshtml) :The following example from the sample app injects IOptionsMonitor<TOptions> into a page model (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #4: Bind options directly to the page
MyOptions = _options;

範例應用程式會顯示如何使用 @inject 指示詞來插入 IOptionsMonitor<MyOptions>The sample app shows how to inject IOptionsMonitor<MyOptions> with an @inject directive:

@page
@model IndexModel
@using Microsoft.Extensions.Options
@inject IOptionsMonitor<MyOptions> OptionsAccessor
@{
    ViewData["Title"] = "Options Sample";
}

<h1>@ViewData["Title"]</h1>

執行應用程式時,轉譯的頁面中會顯示選項值:When the app is run, the options values are shown in the rendered page:

選項值 Option1::value1_from_json 和 Option2: -1 是從模型藉由插入至檢視來載入。

使用 IOptionsSnapshot 重新載入設定資料Reload configuration data with IOptionsSnapshot

使用範例 IOptionsSnapshot<TOptions> 應用程式中的範例5示範重載設定資料。Reloading configuration data with IOptionsSnapshot<TOptions> is demonstrated in Example 5 in the sample app.

使用 IOptionsSnapshot<TOptions> ,在要求的存留期記憶體取和快取選項時,會針對每個要求計算一次。Using IOptionsSnapshot<TOptions>, options are computed once per request when accessed and cached for the lifetime of the request.

和之間的差異在於 IOptionsMonitor IOptionsSnapshotThe difference between IOptionsMonitor and IOptionsSnapshot is that:

  • IOptionsMonitor單一服務 ,可隨時抓取目前的選項值,這在單一相依性中特別有用。IOptionsMonitor is a singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies.
  • IOptionsSnapshot 是限 域的服務 ,會在建立物件時提供選項的快照 IOptionsSnapshot<T>IOptionsSnapshot is a scoped service and provides a snapshot of the options at the time the IOptionsSnapshot<T> object is constructed. 選項快照集的設計目的是要搭配使用暫時性和限定範圍的相依性。Options snapshots are designed for use with transient and scoped dependencies.

下列範例示範如何在 IOptionsSnapshot<TOptions> appsettings.json 變更 (頁面/索引) 之後建立新的。The following example demonstrates how a new IOptionsSnapshot<TOptions> is created after appsettings.json changes (Pages/Index.cshtml.cs). 伺服器的多個要求會傳回檔案所提供的常數值 appsettings.json ,直到檔案變更和設定重載為止。Multiple requests to the server return constant values provided by the appsettings.json file until the file is changed and configuration reloads.

private readonly MyOptions _snapshotOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #5: Snapshot options
var snapshotOption1 = _snapshotOptions.Option1;
var snapshotOption2 = _snapshotOptions.Option2;
SnapshotOptions = 
    $"snapshot option1 = {snapshotOption1}, " +
    $"snapshot option2 = {snapshotOption2}";

下圖顯示從檔案載入的初始 option1option2appsettings.jsonThe following image shows the initial option1 and option2 values loaded from the appsettings.json file:

snapshot option1 = value1_from_json, snapshot option2 = -1

將檔案中的值變更 appsettings.jsonvalue1_from_json UPDATED200Change the values in the appsettings.json file to value1_from_json UPDATED and 200. 儲存 appsettings.json 檔案。Save the appsettings.json file. 重新整理瀏覽器,以查看選項值更新:Refresh the browser to see that the options values are updated:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

IConfigureNamedOptions 的具名選項支援Named options support with IConfigureNamedOptions

IConfigureNamedOptions<TOptions> 的具名選項支援是以範例應用程式中的範例 6 來示範。Named options support with IConfigureNamedOptions<TOptions> is demonstrated as Example 6 in the sample app.

「具名選項」支援可讓應用程式區別具名選項組態。Named options support allows the app to distinguish between named options configurations. 在範例應用程式中,命名選項是使用 OptionsServiceCollectionExtensions.Configu) 來宣告,而這會呼叫 >configurenamedoptions <TOptions> 。設定 擴充方法。In the sample app, named options are declared with OptionsServiceCollectionExtensions.Configure, which calls the ConfigureNamedOptions<TOptions>.Configure extension method. 命名選項會區分大小寫。Named options are case sensitive.

// Example #6: Named options (named_options_1)
// Register the ConfigurationBuilder instance which MyOptions binds against.
// Specify that the options loaded from configuration are named
// "named_options_1".
services.Configure<MyOptions>("named_options_1", Configuration);

// Example #6: Named options (named_options_2)
// Specify that the options loaded from the MyOptions class are named
// "named_options_2".
// Use a delegate to configure option values.
services.Configure<MyOptions>("named_options_2", myOptions =>
{
    myOptions.Option1 = "named_options_2_value1_from_action";
});

範例應用程式會使用 Get (Pages/Index.cshtml.cs) 來存取具名選項:The sample app accesses the named options with Get (Pages/Index.cshtml.cs):

private readonly MyOptions _named_options_1;
private readonly MyOptions _named_options_2;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #6: Named options
var named_options_1 = 
    $"named_options_1: option1 = {_named_options_1.Option1}, " +
    $"option2 = {_named_options_1.Option2}";
var named_options_2 = 
    $"named_options_2: option1 = {_named_options_2.Option1}, " +
    $"option2 = {_named_options_2.Option2}";
NamedOptions = $"{named_options_1} {named_options_2}";

執行範例應用程式後,會傳回具名選項:Running the sample app, the named options are returned:

named_options_1: option1 = value1_from_json, option2 = -1
named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

named_options_1 系統會從設定中提供值,這些值是從檔案載入的 appsettings.jsonnamed_options_1 values are provided from configuration, which are loaded from the appsettings.json file. named_options_2 值是由以下提供:named_options_2 values are provided by:

  • ConfigureServicesOption1named_options_2 委派。The named_options_2 delegate in ConfigureServices for Option1.
  • MyOptions 類別所提供的 Option2 預設值。The default value for Option2 provided by the MyOptions class.

使用 ConfigureAll 方法設定所有選項Configure all options with the ConfigureAll method

使用 ConfigureAll 方法設定所有選項執行個體。Configure all options instances with the ConfigureAll method. 下列程式碼會為具有共通值的所有設定執行個體設定 Option1The following code configures Option1 for all configuration instances with a common value. 將下列程式碼手動新增至 Startup.ConfigureServices 方法:Add the following code manually to the Startup.ConfigureServices method:

services.ConfigureAll<MyOptions>(myOptions => 
{
    myOptions.Option1 = "ConfigureAll replacement value";
});

新增程式碼之後執行範例應用程式,就會產生下列結果:Running the sample app after adding the code produces the following result:

named_options_1: option1 = ConfigureAll replacement value, option2 = -1
named_options_2: option1 = ConfigureAll replacement value, option2 = 5

注意

所有選項都是具名執行個體。All options are named instances. 現有的 IConfigureOptions<TOptions> 執行個體會視為以 Options.DefaultName 執行個體為目標,也就是 string.EmptyExisting IConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. null 具名選項用來以所有具名執行個體為目標,而不是特定的具名執行個體 (ConfigureAllPostConfigureAll 使用此慣例)。The null named option is used to target all of the named instances instead of a specific named instance (ConfigureAll and PostConfigureAll use this convention).

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。OptionsBuilder<TOptions> is used to configure TOptions instances. 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

// Options.DefaultName = "" is used.
services.AddOptions<MyOptions>().Configure(o => o.Property = "default");

services.AddOptions<MyOptions>("optionalName")
    .Configure(o => o.Property = "named");

使用 DI 服務來設定選項Use DI services to configure options

在以下列兩種方式設定選項的同時,您可以從相依性插入中存取其他服務:You can access other services from dependency injection while configuring options in two ways:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。We recommend passing a configuration delegate to Configure, since creating a service is more complex. 建立您自己的類型相當於,當您使用 Configure 時此架構可為您執行的動作。Creating your own type is equivalent to what the framework does for you when you use Configure. 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

選項驗證Options validation

選項驗證可讓您在設定選項之後驗證選項。Options validation allows you to validate options when options are configured. 搭配驗證方法呼叫 Validate,若選項有效會傳回 true,若為無效則傳回 falseCall Validate with a validation method that returns true if options are valid and false if they aren't valid:

// Registration
services.AddOptions<MyOptions>("optionalOptionsName")
    .Configure(o => { }) // Configure the options
    .Validate(o => YourValidationShouldReturnTrueIfValid(o), 
        "custom error");

// Consumption
var monitor = services.BuildServiceProvider()
    .GetService<IOptionsMonitor<MyOptions>>();

try
{
    var options = monitor.Get("optionalOptionsName");
}
catch (OptionsValidationException e) 
{
   // e.OptionsName returns "optionalOptionsName"
   // e.OptionsType returns typeof(MyOptions)
   // e.Failures returns a list of errors, which would contain 
   //     "custom error"
}

上述範例會將具名的選項執行個體設定為 optionalOptionsNameThe preceding example sets the named options instance to optionalOptionsName. 預設選項執行個體為 Options.DefaultNameThe default options instance is Options.DefaultName.

當選項執行個體建立之後,便會執行驗證。Validation runs when the options instance is created. 選項實例保證會在第一次存取時通過驗證。An options instance is guaranteed to pass validation the first time it's accessed.

重要

選項驗證不會在建立選項實例之後防止修改選項。Options validation doesn't guard against options modifications after the options instance is created. 例如,在 IOptionsSnapshot 第一次存取選項時,會針對每個要求建立和驗證選項一次。For example, IOptionsSnapshot options are created and validated once per request when the options are first accessed. 在對 IOptionsSnapshot 相同要求進行 後續的存取嘗試時,不會再次驗證這些選項。The IOptionsSnapshot options aren't validated again on subsequent access attempts for the same request.

Validate 方法可接受 Func<TOptions, bool>The Validate method accepts a Func<TOptions, bool>. 若要完整地自訂驗證,請實作 IValidateOptions<TOptions>,它允許:To fully customize validation, implement IValidateOptions<TOptions>, which allows:

  • 多種選項類型的驗證:class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>Validation of multiple options types: class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>
  • 取決於另一個選項類型的驗證:public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)Validation that depends on another option type: public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)

IValidateOptions 可驗證:IValidateOptions validates:

  • 特定的具名選項執行個體。A specific named options instance.
  • 所有選項 (當 namenull 時)。All options when name is null.

從以下的介面實作傳回 ValidateOptionsResultReturn a ValidateOptionsResult from your implementation of the interface:

public interface IValidateOptions<TOptions> where TOptions : class
{
    ValidateOptionsResult Validate(string name, TOptions options);
}

透過呼叫 OptionsBuilder<TOptions> 上的 ValidateDataAnnotations 方法,就可從 Microsoft.Extensions.Options.DataAnnotations 套件使用資料註解型驗證。Data Annotation-based validation is available from the Microsoft.Extensions.Options.DataAnnotations package by calling the ValidateDataAnnotations method on OptionsBuilder<TOptions>. Microsoft.Extensions.Options.DataAnnotations 包含在 AspNetCore 應用程式中繼套件中。Microsoft.Extensions.Options.DataAnnotations is included in the Microsoft.AspNetCore.App metapackage.

using Microsoft.Extensions.DependencyInjection;

private class AnnotatedOptions
{
    [Required]
    public string Required { get; set; }

    [StringLength(5, ErrorMessage = "Too long.")]
    public string StringLength { get; set; }

    [Range(-5, 5, ErrorMessage = "Out of range.")]
    public int IntRange { get; set; }
}

[Fact]
public void CanValidateDataAnnotations()
{
    var services = new ServiceCollection();
    services.AddOptions<AnnotatedOptions>()
        .Configure(o =>
        {
            o.StringLength = "111111";
            o.IntRange = 10;
            o.Custom = "nowhere";
        })
        .ValidateDataAnnotations();

    var sp = services.BuildServiceProvider();

    var error = Assert.Throws<OptionsValidationException>(() => 
        sp.GetRequiredService<IOptionsMonitor<AnnotatedOptions>>().CurrentValue);
    ValidateFailure<AnnotatedOptions>(error, Options.DefaultName, 1,
        "DataAnnotation validation failed for members Required " +
            "with the error 'The Required field is required.'.",
        "DataAnnotation validation failed for members StringLength " +
            "with the error 'Too long.'.",
        "DataAnnotation validation failed for members IntRange " +
            "with the error 'Out of range.'.");
}

我們考慮在之後的版本中加入積極式驗證 (啟動時快速檢錯)。Eager validation (fail fast at startup) is under consideration for a future release.

選項設定後作業Options post-configuration

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。Set post-configuration with IPostConfigureOptions<TOptions>. 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

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

PostConfigure 可用來後置設定具名選項:PostConfigure is available to post-configure named options:

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

使用 PostConfigureAll 後置設定所有設定執行個體:Use PostConfigureAll to post-configure all configuration instances:

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

在啟動期間存取選項Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. 可能會因為服務註冊的順序而有不一致的選項狀態存在。An inconsistent options state may exist due to the ordering of service registrations.

選項模式使用類別來代表一組相關的設定。The options pattern uses classes to represent groups of related settings. 組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

選項也提供驗證設定資料的機制。Options also provide a mechanism to validate configuration data. 如需詳細資訊,請參閱選項驗證一節。For more information, see the Options validation section.

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

先決條件Prerequisites

參考 Microsoft.AspNetCore.App 中繼套件,或新增 Microsoft.Extensions.Options.ConfigurationExtensions 套件的套件參考。Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Options.ConfigurationExtensions package.

選項介面Options interfaces

IOptionsMonitor<TOptions> 是用來擷取選項並管理 TOptions 執行個體的選項通知。IOptionsMonitor<TOptions> is used to retrieve options and manage options notifications for TOptions instances. IOptionsMonitor<TOptions> 支援以下案例:IOptionsMonitor<TOptions> supports the following scenarios:

設定後案例可讓您在所有 IConfigureOptions<TOptions> 設定發生時設定或變更選項。Post-configuration scenarios allow you to set or change options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> 負責建立新的選項執行個體。IOptionsFactory<TOptions> is responsible for creating new options instances. 它有單一 Create 方法。It has a single Create method. 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). 值可以使用 TryAdd 手動導入。Values can be manually introduced with TryAdd. Clear 方法用於應該視需要重新建立所有具名執行個體時。The Clear method is used when all named instances should be recreated on demand.

IOptionsSnapshot<TOptions> 在應該於收到每個要求時重新計算選項的案例中很實用用。IOptionsSnapshot<TOptions> is useful in scenarios where options should be recomputed on every request. 如需詳細資訊,請參閱使用 IOptionsSnapshot 重新載入設定資料一節。For more information, see the Reload configuration data with IOptionsSnapshot section.

IOptions<TOptions> 可用於支援選項。IOptions<TOptions> can be used to support options. 不過,IOptions<TOptions> 不支援前面的 IOptionsMonitor<TOptions> 案例。However, IOptions<TOptions> doesn't support the preceding scenarios of IOptionsMonitor<TOptions>. 您可以在現有架構與程式庫中繼續使用 IOptions<TOptions>,此程式庫已使用 IOptions<TOptions> 介面且不需要 IOptionsMonitor<TOptions> 提供的案例。You may continue to use IOptions<TOptions> in existing frameworks and libraries that already use the IOptions<TOptions> interface and don't require the scenarios provided by IOptionsMonitor<TOptions>.

一般選項設定General options configuration

一般選項設定是以範例應用程式中的範例 1 來示範。General options configuration is demonstrated as Example 1 in the sample app.

選項類別必須為非抽象,且具有公用的無參數建構函式。An options class must be non-abstract with a public parameterless constructor. 下列 MyOptions 類別有兩個屬性,Option1Option2The following class, MyOptions, has two properties, Option1 and Option2. 設定預設值為選擇性,但在下列範例中,類別建構函式會設定 Option1 的預設值。Setting default values is optional, but the class constructor in the following example sets the default value of Option1. Option2 的預設值直接藉由初始化屬性來設定 (Models/MyOptions.cs):Option2 has a default value set by initializing the property directly (Models/MyOptions.cs):

public class MyOptions
{
    public MyOptions()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

MyOptions 類別使用 Configure 新增到服務容器,並繫結到設定:The MyOptions class is added to the service container with Configure and bound to configuration:

// Example #1: General configuration
// Register the Configuration instance which MyOptions binds against.
services.Configure<MyOptions>(Configuration);

下列頁面模型使用 建構函式相依性插入搭配 IOptionsMonitor<TOptions> 來存取設定 (Pages/Index.cshtml.cs):The following page model uses constructor dependency injection with IOptionsMonitor<TOptions> to access the settings (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #1: Simple options
var option1 = _options.Option1;
var option2 = _options.Option2;
SimpleOptions = $"option1 = {option1}, option2 = {option2}";

範例的檔案會 appsettings.json 指定和的 option1option2The sample's appsettings.json file specifies values for option1 and option2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:When the app is run, the page model's OnGet method returns a string showing the option class values:

option1 = value1_from_json, option2 = -1

注意

使用自訂 ConfigurationBuilder 從設定檔載入選項設定時,請確認已正確設定基底路徑:When using a custom ConfigurationBuilder to load options configuration from a settings file, confirm that the base path is set correctly:

var configBuilder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: true);
var config = configBuilder.Build();

services.Configure<MyOptions>(config);

透過 CreateDefaultBuilder 從設定檔載入選項設定時,不需要明確設定基底路徑。Explicitly setting the base path isn't required when loading options configuration from the settings file via CreateDefaultBuilder.

使用委派設定簡單的選項Configure simple options with a delegate

使用委派設定簡單的選項是以範例應用程式中的範例 2 來示範。Configuring simple options with a delegate is demonstrated as Example 2 in the sample app.

使用委派來設定選項值。Use a delegate to set options values. 範例應用程式使用 MyOptionsWithDelegateConfig 類別 (Models/MyOptionsWithDelegateConfig.cs):The sample app uses the MyOptionsWithDelegateConfig class (Models/MyOptionsWithDelegateConfig.cs):

public class MyOptionsWithDelegateConfig
{
    public MyOptionsWithDelegateConfig()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

在下列程式碼中,第二個 IConfigureOptions<TOptions> 服務新增至服務容器。In the following code, a second IConfigureOptions<TOptions> service is added to the service container. 它使用委派,以 MyOptionsWithDelegateConfig 設定繫結:It uses a delegate to configure the binding with MyOptionsWithDelegateConfig:

// Example #2: Options bound and configured by a delegate
services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
{
    myOptions.Option1 = "value1_configured_by_delegate";
    myOptions.Option2 = 500;
});

Index.cshtml.csIndex.cshtml.cs:

private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #2: Options configured by delegate
var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
SimpleOptionsWithDelegateConfig = 
    $"delegate_option1 = {delegate_config_option1}, " +
    $"delegate_option2 = {delegate_config_option2}";

您可以新增多個設定提供者。You can add multiple configuration providers. 設定提供者可在 NuGet 套件中找到,而且會依註冊順序套用。Configuration providers are available from NuGet packages and are applied in the order that they're registered. 如需詳細資訊,請參閱 ASP.NET Core 的設定For more information, see ASP.NET Core 的設定.

每次呼叫 Configure 時都會新增 IConfigureOptions<TOptions> 服務到服務容器。Each call to Configure adds an IConfigureOptions<TOptions> service to the service container. 在上述範例中,和的值 Option1Option2 是指定于中 appsettings.json ,但是和的值 Option1 Option2 會由設定的委派覆寫。In the preceding example, the values of Option1 and Option2 are both specified in appsettings.json, but the values of Option1 and Option2 are overridden by the configured delegate.

啟用多個設定服務時,最後一個指定的設定來源會「勝出」並設定此組態值。When more than one configuration service is enabled, the last configuration source specified wins and sets the configuration value. 當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:When the app is run, the page model's OnGet method returns a string showing the option class values:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子選項組態Suboptions configuration

子選項組態是以範例應用程式中的範例 3 來示範。Suboptions configuration is demonstrated as Example 3 in the sample app.

應用程式應該建立屬於應用程式中特定案例群組 (類別) 的選項類別。Apps should create options classes that pertain to specific scenario groups (classes) in the app. 需要組態值的應用程式組件應該只能存取它們使用的設定值。Parts of the app that require configuration values should only have access to the configuration values that they use.

將選項繫結至組態時,選項類型中的每一個屬性都會繫結至 property[:sub-property:] 格式的組態索引鍵。When binding options to configuration, each property in the options type is bound to a configuration key of the form property[:sub-property:]. 例如, MyOptions.Option1 屬性會系結至索引鍵,這個索引鍵 Option1 是從的 option1 屬性中讀取的 appsettings.jsonFor example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json.

在下列程式碼中,第三個 IConfigureOptions<TOptions> 服務新增至服務容器。In the following code, a third IConfigureOptions<TOptions> service is added to the service container. 它會系結至檔案的 MySubOptions 區段 subsection appsettings.jsonIt binds MySubOptions to the section subsection of the appsettings.json file:

// Example #3: Suboptions
// Bind options using a sub-section of the appsettings.json file.
services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

GetSection方法需要 Microsoft.Extensions.Configuration 命名空間。The GetSection method requires the Microsoft.Extensions.Configuration namespace.

範例的檔案會 appsettings.json 定義 subsection 具有和之索引鍵的成員 suboption1 suboption2The sample's appsettings.json file defines a subsection member with keys for suboption1 and suboption2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

MySubOptions 類別會定義屬性 SubOption1SubOption2,來保存選項值 (Models/MySubOptions.cs):The MySubOptions class defines properties, SubOption1 and SubOption2, to hold the options values (Models/MySubOptions.cs):

public class MySubOptions
{
    public MySubOptions()
    {
        // Set default values.
        SubOption1 = "value1_from_ctor";
        SubOption2 = 5;
    }
    
    public string SubOption1 { get; set; }
    public int SubOption2 { get; set; }
}

頁面模型的 OnGet 方法會傳回具有選項值 (Pages/Index.cshtml.cs) 的字串:The page model's OnGet method returns a string with the options values (Pages/Index.cshtml.cs):

private readonly MySubOptions _subOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #3: Suboptions
var subOption1 = _subOptions.SubOption1;
var subOption2 = _subOptions.SubOption2;
SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

當應用程式執行時,OnGet 方法會傳回字串,顯示子選項類別值:When the app is run, the OnGet method returns a string showing the suboption class values:

subOption1 = subvalue1_from_json, subOption2 = 200

檢視模型提供的選項或使用直接檢視插入提供的選項Options provided by a view model or with direct view injection

檢視模型提供的選項或使用直接檢視插入提供的選項是以範例應用程式中的範例 4 來示範。Options provided by a view model or with direct view injection is demonstrated as Example 4 in the sample app.

可以在檢視模型中提供選項,或藉由將 IOptionsMonitor<TOptions> 直接插入至檢視來提供選項 (Pages/Index.cshtml.cs):Options can be supplied in a view model or by injecting IOptionsMonitor<TOptions> directly into a view (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #4: Bind options directly to the page
MyOptions = _options;

範例應用程式會顯示如何使用 @inject 指示詞來插入 IOptionsMonitor<MyOptions>The sample app shows how to inject IOptionsMonitor<MyOptions> with an @inject directive:

@page
@model IndexModel
@using Microsoft.Extensions.Options
@inject IOptionsMonitor<MyOptions> OptionsAccessor
@{
    ViewData["Title"] = "Options Sample";
}

<h1>@ViewData["Title"]</h1>

執行應用程式時,轉譯的頁面中會顯示選項值:When the app is run, the options values are shown in the rendered page:

選項值 Option1::value1_from_json 和 Option2: -1 是從模型藉由插入至檢視來載入。

使用 IOptionsSnapshot 重新載入設定資料Reload configuration data with IOptionsSnapshot

使用範例 IOptionsSnapshot<TOptions> 應用程式中的範例5示範重載設定資料。Reloading configuration data with IOptionsSnapshot<TOptions> is demonstrated in Example 5 in the sample app.

IOptionsSnapshot<TOptions> 支援以最小的處理負擔來重新載入選項。IOptionsSnapshot<TOptions> supports reloading options with minimal processing overhead.

在要求的存留期內存取及快取選項時,會針對每個要求計算一次選項。Options are computed once per request when accessed and cached for the lifetime of the request.

下列範例示範如何在 IOptionsSnapshot<TOptions> appsettings.json 變更 (頁面/索引) 之後建立新的。The following example demonstrates how a new IOptionsSnapshot<TOptions> is created after appsettings.json changes (Pages/Index.cshtml.cs). 伺服器的多個要求會傳回檔案所提供的常數值 appsettings.json ,直到檔案變更和設定重載為止。Multiple requests to the server return constant values provided by the appsettings.json file until the file is changed and configuration reloads.

private readonly MyOptions _snapshotOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #5: Snapshot options
var snapshotOption1 = _snapshotOptions.Option1;
var snapshotOption2 = _snapshotOptions.Option2;
SnapshotOptions = 
    $"snapshot option1 = {snapshotOption1}, " +
    $"snapshot option2 = {snapshotOption2}";

下圖顯示從檔案載入的初始 option1option2appsettings.jsonThe following image shows the initial option1 and option2 values loaded from the appsettings.json file:

snapshot option1 = value1_from_json, snapshot option2 = -1

將檔案中的值變更 appsettings.jsonvalue1_from_json UPDATED200Change the values in the appsettings.json file to value1_from_json UPDATED and 200. 儲存 appsettings.json 檔案。Save the appsettings.json file. 重新整理瀏覽器,以查看選項值更新:Refresh the browser to see that the options values are updated:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

IConfigureNamedOptions 的具名選項支援Named options support with IConfigureNamedOptions

IConfigureNamedOptions<TOptions> 的具名選項支援是以範例應用程式中的範例 6 來示範。Named options support with IConfigureNamedOptions<TOptions> is demonstrated as Example 6 in the sample app.

「具名選項」支援可讓應用程式區別具名選項組態。Named options support allows the app to distinguish between named options configurations. 在範例應用程式中,命名選項是使用 OptionsServiceCollectionExtensions.Configu) 來宣告,而這會呼叫 >configurenamedoptions <TOptions> 。設定 擴充方法。In the sample app, named options are declared with OptionsServiceCollectionExtensions.Configure, which calls the ConfigureNamedOptions<TOptions>.Configure extension method. 命名選項會區分大小寫。Named options are case sensitive.

// Example #6: Named options (named_options_1)
// Register the ConfigurationBuilder instance which MyOptions binds against.
// Specify that the options loaded from configuration are named
// "named_options_1".
services.Configure<MyOptions>("named_options_1", Configuration);

// Example #6: Named options (named_options_2)
// Specify that the options loaded from the MyOptions class are named
// "named_options_2".
// Use a delegate to configure option values.
services.Configure<MyOptions>("named_options_2", myOptions =>
{
    myOptions.Option1 = "named_options_2_value1_from_action";
});

範例應用程式會使用 Get (Pages/Index.cshtml.cs) 來存取具名選項:The sample app accesses the named options with Get (Pages/Index.cshtml.cs):

private readonly MyOptions _named_options_1;
private readonly MyOptions _named_options_2;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #6: Named options
var named_options_1 = 
    $"named_options_1: option1 = {_named_options_1.Option1}, " +
    $"option2 = {_named_options_1.Option2}";
var named_options_2 = 
    $"named_options_2: option1 = {_named_options_2.Option1}, " +
    $"option2 = {_named_options_2.Option2}";
NamedOptions = $"{named_options_1} {named_options_2}";

執行範例應用程式後,會傳回具名選項:Running the sample app, the named options are returned:

named_options_1: option1 = value1_from_json, option2 = -1
named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

named_options_1 系統會從設定中提供值,這些值是從檔案載入的 appsettings.jsonnamed_options_1 values are provided from configuration, which are loaded from the appsettings.json file. named_options_2 值是由以下提供:named_options_2 values are provided by:

  • ConfigureServicesOption1named_options_2 委派。The named_options_2 delegate in ConfigureServices for Option1.
  • MyOptions 類別所提供的 Option2 預設值。The default value for Option2 provided by the MyOptions class.

使用 ConfigureAll 方法設定所有選項Configure all options with the ConfigureAll method

使用 ConfigureAll 方法設定所有選項執行個體。Configure all options instances with the ConfigureAll method. 下列程式碼會為具有共通值的所有設定執行個體設定 Option1The following code configures Option1 for all configuration instances with a common value. 將下列程式碼手動新增至 Startup.ConfigureServices 方法:Add the following code manually to the Startup.ConfigureServices method:

services.ConfigureAll<MyOptions>(myOptions => 
{
    myOptions.Option1 = "ConfigureAll replacement value";
});

新增程式碼之後執行範例應用程式,就會產生下列結果:Running the sample app after adding the code produces the following result:

named_options_1: option1 = ConfigureAll replacement value, option2 = -1
named_options_2: option1 = ConfigureAll replacement value, option2 = 5

注意

所有選項都是具名執行個體。All options are named instances. 現有的 IConfigureOptions<TOptions> 執行個體會視為以 Options.DefaultName 執行個體為目標,也就是 string.EmptyExisting IConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. null 具名選項用來以所有具名執行個體為目標,而不是特定的具名執行個體 (ConfigureAllPostConfigureAll 使用此慣例)。The null named option is used to target all of the named instances instead of a specific named instance (ConfigureAll and PostConfigureAll use this convention).

OptionsBuilder APIOptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。OptionsBuilder<TOptions> is used to configure TOptions instances. 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

// Options.DefaultName = "" is used.
services.AddOptions<MyOptions>().Configure(o => o.Property = "default");

services.AddOptions<MyOptions>("optionalName")
    .Configure(o => o.Property = "named");

使用 DI 服務來設定選項Use DI services to configure options

在以下列兩種方式設定選項的同時,您可以從相依性插入中存取其他服務:You can access other services from dependency injection while configuring options in two ways:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。We recommend passing a configuration delegate to Configure, since creating a service is more complex. 建立您自己的類型相當於,當您使用 Configure 時此架構可為您執行的動作。Creating your own type is equivalent to what the framework does for you when you use Configure. 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

選項設定後作業Options post-configuration

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。Set post-configuration with IPostConfigureOptions<TOptions>. 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

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

PostConfigure 可用來後置設定具名選項:PostConfigure is available to post-configure named options:

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

使用 PostConfigureAll 後置設定所有設定執行個體:Use PostConfigureAll to post-configure all configuration instances:

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

在啟動期間存取選項Accessing options during startup

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. 可能會因為服務註冊的順序而有不一致的選項狀態存在。An inconsistent options state may exist due to the ordering of service registrations.

其他資源Additional resources