ASP.NET Core のオプション パターンOptions pattern in ASP.NET Core

作成者: Luke LathamBy Luke Latham

バージョン 1.1 のトピックについては、ASP.NET Core のオプション パターン (バージョン1.1) の PDF ファイルをダウンロードしてください。For the 1.1 version of this topic, download Options pattern in ASP.NET Core (version 1.1, PDF).

オプション パターンではクラスを使用して、関連する設定のグループを表します。The options pattern uses classes to represent groups of related settings. 構成設定がシナリオ別に個々のクラスに分離されるとき、アプリは次の 2 つの重要なソフトウェア エンジニアリング原則に従います。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 メソッドが 1 つ含まれています。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> インターフェイスを使用しており、IOptionsMonitor<TOptions> によって提供されるシナリオが必要ない既存のフレームワークとライブラリでは、IOptions<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 には Option1Option2 という 2 つのプロパティがあります。The 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 ファイルは option1option2 の値を指定します。The 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;
}

次のコードでは、2 番目の 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.cs:Index.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 で指定されていますが、構成されているデリゲートにより値 Option1Option2 がオーバーライドされます。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_delgate, 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 にバインドされます。このキーは appsettings.jsonoption1 プロパティから読み込まれます。For example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json.

次のコードでは、3 番目の IConfigureOptions<TOptions> サービスがサービス コンテナーに追加されます。In the following code, a third IConfigureOptions<TOptions> service is added to the service container. MySubOptionsappsettings.json ファイルのセクション subsection にバインドします。It 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.Options.ConfigurationExtensions NuGet パッケージを必要とします。The GetSection extension method requires the Microsoft.Extensions.Options.ConfigurationExtensions NuGet package. アプリで Microsoft.AspNetCore.App メタパッケージ (ASP.NET Core 2.1 以降) を使用している場合、このパッケージは自動的に含まれます。If the app uses the Microsoft.AspNetCore.App metapackage (ASP.NET Core 2.1 or later), the package is automatically included.

サンプルの appsettings.json ファイルは、suboption1suboption2 のキーで subsection メンバーを定義します。The 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 クラスは、SubOption1 プロパティと SubOption2 プロパティを定義し、オプションの値を保持します (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

サンプル アプリの例 #5 では、IOptionsSnapshot<TOptions> で構成データを再読み込みする方法を確認できます。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.

オプションは、要求の有効期間中にアクセスされ、キャッシュされたとき、要求につき 1 回計算されます。Options are computed once per request when accessed and cached for the lifetime of the request.

次の例では、appsettings.json の変更後、新しい IOptionsSnapshot<TOptions> が作成されます (Pages/Index.cshtml.cs)。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.json ファイルから読み込まれます。The following image shows the initial option1 and option2 values loaded from the appsettings.json file:

snapshot option1 = value1_from_json, snapshot option2 = -1

appsettings.json ファイルの値を value1_from_json UPDATED200 に変更します。Change 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

サンプル アプリの例 #6 は、IConfigureNamedOptions<TOptions> による名前付きオプションのサポートです。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.Configure で宣言されます。これは、ConfigureNamedOptions<TOptions>.Configure 拡張メソッドを呼び出します。In the sample app, named options are declared with OptionsServiceCollectionExtensions.Configure, which calls the ConfigureNamedOptions<TOptions>.Configure extension method:

// 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.json ファイルから読み込まれます。named_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:

  • Option1ConfigureServicesnamed_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. 次のコードでは、すべての構成インスタンスの Option1 が共通値で構成されます。The 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> インスタンスは、string.Empty である、Options.DefaultName インスタンスを対象とするものとして処理されます。Existing 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) の呼び出しに対する 1 つのパラメーターにすぎず、後続のすべての呼び出しが表示されなくなるためです。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");

<TOptions, TDep1, ...TDep4> メソッドを構成するConfigure<TOptions, TDep1, ... TDep4> method

DI からサービスを使用して、定型的に IConfigure[Named]Options を実装することでオプションを構成する方法では、冗長です。Using services from DI to configure options by implementing IConfigure[Named]Options in a boilerplate manner is verbose. OptionsBuilder<TOptions> での ConfigureOptions のオーバーロードにより、オプションを構成するために、サービスを 5 つまで使用することができます。Overloads for ConfigureOptions on OptionsBuilder<TOptions> allow you to use up to five services to configure options:

services.AddOptions<MyOptions>("optionalName")
    .Configure<Service1, Service2, Service3, Service4, Service5>(
        (o, s, s2, s3, s4, s5) => 
            o.Property = DoSomethingWith(s, s2, s3, s4, s5));

このオーバーロードでは、指定された汎用的なサービスの種類を受け入れるコンストラクターを含む、一時的な汎用の IConfigureNamedOptions<TOptions> が登録されます。The overload 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. オプションが有効なら true を、無効なら false を返す検証メソッドと共に、Validate を呼び出します。Call 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"
}

前の例では、名前付きのオプションのインスタンスを optionalOptionsName に設定しました。The preceding example sets the named options instance to optionalOptionsName. 既定のオプションのインスタンスは Options.DefaultName です。The default options instance is Options.DefaultName.

オプションのインスタンスが作成されると、検証が実行されます。Validation runs when the options instance is created. オプションのインスタンスが最初にアクセスされる際は、検証に合格することが保証されます。Your options instance is guaranteed to pass validation the first time it's accessed.

重要

オプションの検証は、最初に構成されて検証された後のオプションの変更を防ぐことはできません。Options validation doesn't guard against options modifications after the options are initially configured and validated.

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.

インターフェイスの実装から ValidateOptionsResult を返します。Return 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 は、Microsoft.AspNetCore.App メタパッケージに含まれます (ASP.NET Core 2.2 以降)。Microsoft.Extensions.Options.DataAnnotations is included in the Microsoft.AspNetCore.App metapackage (ASP.NET Core 2.2 or later).

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>>().Value);
    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

サービスは Configure メソッドの実行前に構築されるため、IOptions<TOptions> および IOptionsMonitor<TOptions>Startup.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