ASP.NET Core 中的選項模式

Kirk LarkinRick Anderson

選項模式使用類別來提供相關設定群組的強型別存取。 當組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:

選項也提供驗證設定資料的機制。 如需詳細資訊,請參閱選項驗證一節。

本主題提供 ASP.NET Core 中選項模式的相關資訊。 如需在主控台應用程式中使用選項模式的詳細資訊,請參閱 .net 中的選項模式

查看或下載範例程式碼 (如何下載)

系結階層式設定

讀取相關設定值的慣用方式是使用 選項模式。 例如,若要讀取下列設定值:

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

建立下列 PositionOptions 類別:

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

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

Options 類別:

  • 必須是具有公用無參數的函式的非抽象。
  • 型別的所有公用讀寫屬性都會系結。
  • 欄位 系結。 在上述程式碼中,未系結 Position 。 使用屬性,因此在將類別系結 Position "Position" 至設定提供者時,不需要在應用程式中硬式編碼字串。

下列程式碼:

  • 呼叫 ConfigurationBinder ,將類別系結至 PositionOptions Position 區段。
  • 顯示 Position 設置資料。
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 設定檔變更。

ConfigurationBinder.Get<T> 系結並傳回指定的型別。 ConfigurationBinder.Get<T> 可能比使用更方便 ConfigurationBinder.Bind 。 下列程式碼顯示如何搭配 ConfigurationBinder.Get<T> PositionOptions 類別使用:

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 設定檔變更。

使用 *選項模式 _ 的替代方法是系結 Position 區段,並將它加入至相依性 插入服務容器。 在下列程式碼中, PositionOptions 會新增至服務容器, <xref:Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure_> 並系結至設定:

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

使用上述程式碼,下列程式碼會讀取位置選項:

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 設定檔變更。 若要讀取應用程式啟動後的變更,請使用 IOptionsSnapshot

選項介面

IOptions<TOptions>:

IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:

設定案例會在進行所有設定之後,啟用設定或變更選項 IConfigureOptions<TOptions>

IOptionsFactory<TOptions> 負責建立新的選項執行個體。 它有單一 Create 方法。 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。 IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。 值可以使用 TryAdd 手動導入。 Clear 方法用於應該視需要重新建立所有具名執行個體時。

使用 IOptionsSnapshot 讀取更新的資料

使用 IOptionsSnapshot<TOptions> ,在要求的存留期記憶體取和快取選項時,會針對每個要求計算一次。 使用支援讀取已更新設定值的設定提供者時,會在應用程式啟動後讀取設定的變更。

和之間的差異在於 IOptionsMonitor IOptionsSnapshot

  • IOptionsMonitor單一服務 ,可隨時抓取目前的選項值,這在單一相依性中特別有用。
  • IOptionsSnapshot 是限 域的服務 ,會在建立物件時提供選項的快照 IOptionsSnapshot<T> 。 選項快照集的設計目的是要搭配使用暫時性和限定範圍的相依性。

下列程式碼使用 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}");
    }
}

下列程式碼會註冊系結的設定實例 MyOptions

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

    services.AddRazorPages();
}

在上述程式碼中,會讀取應用程式啟動後的 JSON 設定檔變更。

IOptionsMonitor

下列程式碼會註冊針對系結的設定實例 MyOptions

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

    services.AddRazorPages();
}

下列範例會使用 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 設定檔變更。

使用 IConfigureNamedOptions 的命名選項支援

命名選項:

  • 當多個設定區段系結至相同的屬性時,會很有用。
  • 會區分大小寫。

請考慮下列檔案 appsettings.json

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

TopItem:Month TopItem:Year 下列類別可用於每個區段,而不是建立兩個類別來系結和:

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

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

下列程式碼會設定命名選項:

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

下列程式碼會顯示已命名的選項:

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

所有選項都是具名執行個體。 IConfigureOptions<TOptions> 系統會將實例視為目標 Options.DefaultName 實例,也就是 string.EmptyIConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。 此 null 命名選項用來以所有已命名的實例為目標,而不是特定的已命名實例。 ConfigureAllPostConfigureAll 使用此慣例。

OptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。

OptionsBuilder 在 [ 選項驗證 ] 區段中使用。

請參閱 使用 AddOptions 設定自 定義存放庫以取得新增自訂存放庫的資訊。

使用 DI 服務來設定選項

您可以透過下列兩種方式,從相依性插入來存取服務:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。 建立類型相當於呼叫 設定時的架構。 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。

選項驗證

選項驗證可讓您驗證選項值。

請考慮下列檔案 appsettings.json

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

下列類別會系結至設定 "MyConfig" 區段,並套用一些 DataAnnotations 規則:

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

下列程式碼:

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 套件中定義。 針對使用 SDK 的 web 應用程式 Microsoft.NET.Sdk.Web ,會從共用架構隱含參考此套件。

下列程式碼顯示設定值或驗證錯誤:

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

下列程式碼會使用委派來套用更複雜的驗證規則:

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

複雜驗證的 IValidateOptions

下列類別會實行 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 至類別。

使用上述程式碼,即可在中使用下列程式碼來啟用驗證 Startup.ConfigureServices

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

選項設定後作業

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:

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

PostConfigure 可用來後置設定具名選項:

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

使用 PostConfigureAll 後置設定所有設定執行個體:

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

在啟動期間存取選項

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>。 可能會因為服務註冊的順序而有不一致的選項狀態存在。

Options.ConfigurationExtensions NuGet 封裝

ASP.NET Core 應用程式中會隱含參考Microsoft.Extensions.Options.ConfigurationExtensions套件。

選項模式使用類別來代表一組相關的設定。 當組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:

選項也提供驗證設定資料的機制。 如需詳細資訊,請參閱選項驗證一節。

查看或下載範例程式碼 (如何下載)

必要條件

參考 Microsoft.AspNetCore.App 中繼套件,或新增 Microsoft.Extensions.Options.ConfigurationExtensions 套件的套件參考。

選項介面

IOptionsMonitor<TOptions> 是用來擷取選項並管理 TOptions 執行個體的選項通知。 IOptionsMonitor<TOptions> 支援以下案例:

設定後案例可讓您在所有 IConfigureOptions<TOptions> 設定發生時設定或變更選項。

IOptionsFactory<TOptions> 負責建立新的選項執行個體。 它有單一 Create 方法。 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。 IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。 值可以使用 TryAdd 手動導入。 Clear 方法用於應該視需要重新建立所有具名執行個體時。

IOptionsSnapshot<TOptions> 在應該於收到每個要求時重新計算選項的案例中很實用用。 如需詳細資訊,請參閱使用 IOptionsSnapshot 重新載入設定資料一節。

IOptions<TOptions> 可用於支援選項。 不過,IOptions<TOptions> 不支援前面的 IOptionsMonitor<TOptions> 案例。 您可以在現有架構與程式庫中繼續使用 IOptions<TOptions>,此程式庫已使用 IOptions<TOptions> 介面且不需要 IOptionsMonitor<TOptions> 提供的案例。

一般選項設定

一般選項設定是以範例應用程式中的範例 1 來示範。

選項類別必須為非抽象,且具有公用的無參數建構函式。 下列 MyOptions 類別有兩個屬性,Option1Option2。 設定預設值為選擇性,但在下列範例中,類別建構函式會設定 Option1 的預設值。 Option2 的預設值直接藉由初始化屬性來設定 (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 新增到服務容器,並繫結到設定:

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

下列頁面模型使用 建構函式相依性插入搭配 IOptionsMonitor<TOptions> 來存取設定 (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

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

當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:

option1 = value1_from_json, option2 = -1

注意

使用自訂 ConfigurationBuilder 從設定檔載入選項設定時,請確認已正確設定基底路徑:

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

services.Configure<MyOptions>(config);

透過 CreateDefaultBuilder 從設定檔載入選項設定時,不需要明確設定基底路徑。

使用委派設定簡單的選項

使用委派設定簡單的選項是以範例應用程式中的範例 2 來示範。

使用委派來設定選項值。 範例應用程式使用 MyOptionsWithDelegateConfig 類別 (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> 服務新增至服務容器。 它使用委派,以 MyOptionsWithDelegateConfig 設定繫結:

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

的索引。 .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}";

您可以新增多個設定提供者。 設定提供者可在 NuGet 套件中找到,而且會依註冊順序套用。 如需詳細資訊,請參閱ASP.NET Core 的設定

每次呼叫 Configure 時都會新增 IConfigureOptions<TOptions> 服務到服務容器。 在上述範例中,和的值 Option1Option2 是指定于中 appsettings.json ,但是和的值 Option1 Option2 會由設定的委派覆寫。

啟用多個設定服務時,最後一個指定的設定來源會「勝出」並設定此組態值。 當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子選項組態

子選項組態是以範例應用程式中的範例 3 來示範。

應用程式應該建立屬於應用程式中特定案例群組 (類別) 的選項類別。 需要組態值的應用程式組件應該只能存取它們使用的設定值。

將選項繫結至組態時,選項類型中的每一個屬性都會繫結至 property[:sub-property:] 格式的組態索引鍵。 例如, MyOptions.Option1 屬性會系結至索引鍵,這個索引鍵 Option1 是從的 option1 屬性中讀取的 appsettings.json

在下列程式碼中,第三個 IConfigureOptions<TOptions> 服務新增至服務容器。 它會系結至檔案的 MySubOptions 區段 subsection appsettings.json

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

GetSection方法需要 Microsoft.Extensions.Configuration 命名空間。

範例的檔案會 appsettings.json 定義 subsection 具有和之索引鍵的成員 suboption1 suboption2

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

MySubOptions 類別會定義屬性 SubOption1SubOption2,來保存選項值 (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) 的字串:

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 方法會傳回字串,顯示子選項類別值:

subOption1 = subvalue1_from_json, subOption2 = 200

選項插入

選項插入在範例應用程式中會示範為範例4。

插入 IOptionsMonitor<TOptions>

  • 具有指示詞的 Razor 頁面或 MVC 視圖 @inject Razor 。
  • 頁面或視圖模型。

範例應用程式中的下列範例會插入 IOptionsMonitor<TOptions> 頁面模型中, (Pages/Index. cshtml) :

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>

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

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

執行應用程式時,轉譯的頁面中會顯示選項值:

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

使用 IOptionsSnapshot 重新載入設定資料

使用範例 IOptionsSnapshot<TOptions> 應用程式中的範例5示範重載設定資料。

使用 IOptionsSnapshot<TOptions> ,在要求的存留期記憶體取和快取選項時,會針對每個要求計算一次。

和之間的差異在於 IOptionsMonitor IOptionsSnapshot

  • IOptionsMonitor單一服務 ,可隨時抓取目前的選項值,這在單一相依性中特別有用。
  • IOptionsSnapshot 是限 域的服務 ,會在建立物件時提供選項的快照 IOptionsSnapshot<T> 。 選項快照集的設計目的是要搭配使用暫時性和限定範圍的相依性。

下列範例示範如何在 IOptionsSnapshot<TOptions> appsettings.json 變更 (頁面/索引) 之後建立新的。 伺服器的多個要求會傳回檔案所提供的常數值 appsettings.json ,直到檔案變更和設定重載為止。

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

snapshot option1 = value1_from_json, snapshot option2 = -1

將檔案中的值變更 appsettings.jsonvalue1_from_json UPDATED200 。 儲存 appsettings.json 檔案。 重新整理瀏覽器,以查看選項值更新:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

IConfigureNamedOptions 的具名選項支援

IConfigureNamedOptions<TOptions> 的具名選項支援是以範例應用程式中的範例 6 來示範。

「具名選項」支援可讓應用程式區別具名選項組態。 在範例應用程式中,命名選項是使用 OptionsServiceCollectionExtensions.Configu) 來宣告,而這會呼叫 >configurenamedoptions <TOptions> 。設定 擴充方法。 命名選項會區分大小寫。

// 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) 來存取具名選項:

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

執行範例應用程式後,會傳回具名選項:

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_2 值是由以下提供:

  • ConfigureServicesOption1named_options_2 委派。
  • MyOptions 類別所提供的 Option2 預設值。

使用 ConfigureAll 方法設定所有選項

使用 ConfigureAll 方法設定所有選項執行個體。 下列程式碼會為具有共通值的所有設定執行個體設定 Option1。 將下列程式碼手動新增至 Startup.ConfigureServices 方法:

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

新增程式碼之後執行範例應用程式,就會產生下列結果:

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

注意

所有選項都是具名執行個體。 現有的 IConfigureOptions<TOptions> 執行個體會視為以 Options.DefaultName 執行個體為目標,也就是 string.EmptyIConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。 null 具名選項用來以所有具名執行個體為目標,而不是特定的具名執行個體 (ConfigureAllPostConfigureAll 使用此慣例)。

OptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。

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

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

使用 DI 服務來設定選項

在以下列兩種方式設定選項的同時,您可以從相依性插入中存取其他服務:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。 建立您自己的類型相當於,當您使用 Configure 時此架構可為您執行的動作。 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。

選項驗證

選項驗證可讓您在設定選項之後驗證選項。 搭配驗證方法呼叫 Validate,若選項有效會傳回 true,若為無效則傳回 false

// 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。 預設選項執行個體為 Options.DefaultName

當選項執行個體建立之後,便會執行驗證。 選項實例保證會在第一次存取時通過驗證。

重要

選項驗證不會在建立選項實例之後防止修改選項。 例如,在 IOptionsSnapshot 第一次存取選項時,會針對每個要求建立和驗證選項一次。 在對 IOptionsSnapshot 相同要求進行 後續的存取嘗試時,不會再次驗證這些選項。

Validate 方法可接受 Func<TOptions, bool>。 若要完整地自訂驗證,請實作 IValidateOptions<TOptions>,它允許:

  • 多種選項類型的驗證:class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>
  • 取決於另一個選項類型的驗證:public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)

IValidateOptions 可驗證:

  • 特定的具名選項執行個體。
  • 所有選項 (當 namenull 時)。

從以下的介面實作傳回 ValidateOptionsResult

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

透過呼叫 OptionsBuilder<TOptions> 上的 ValidateDataAnnotations 方法,就可從 Microsoft.Extensions.Options.DataAnnotations 套件使用資料註解型驗證。 Microsoft.Extensions.Options.DataAnnotations 包含在 Microsoft.AspNetCore.App 中繼套件中。

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

我們考慮在之後的版本中加入積極式驗證 (啟動時快速檢錯)。

選項設定後作業

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:

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

PostConfigure 可用來後置設定具名選項:

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

使用 PostConfigureAll 後置設定所有設定執行個體:

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

在啟動期間存取選項

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>。 可能會因為服務註冊的順序而有不一致的選項狀態存在。

選項模式使用類別來代表一組相關的設定。 當組態設定依案例隔離到不同的類別時,應用程式會遵守兩個重要的軟體工程準則:

選項也提供驗證設定資料的機制。 如需詳細資訊,請參閱選項驗證一節。

查看或下載範例程式碼 (如何下載)

必要條件

參考 Microsoft.AspNetCore.App 中繼套件,或新增 Microsoft.Extensions.Options.ConfigurationExtensions 套件的套件參考。

選項介面

IOptionsMonitor<TOptions> 是用來擷取選項並管理 TOptions 執行個體的選項通知。 IOptionsMonitor<TOptions> 支援以下案例:

設定後案例可讓您在所有 IConfigureOptions<TOptions> 設定發生時設定或變更選項。

IOptionsFactory<TOptions> 負責建立新的選項執行個體。 它有單一 Create 方法。 預設實作會接受所有已註冊的 IConfigureOptions<TOptions>IPostConfigureOptions<TOptions>,並先執行所有設定,接著執行設定後作業。 它會區別 IConfigureNamedOptions<TOptions>IConfigureOptions<TOptions>,且只會呼叫適當的介面。

IOptionsMonitorCache<TOptions> 會由 IOptionsMonitor<TOptions> 用來快取 TOptions 執行個體。 IOptionsMonitorCache<TOptions> 會使監視器中的選項執行個體失效,以便重新計算值 (TryRemove)。 值可以使用 TryAdd 手動導入。 Clear 方法用於應該視需要重新建立所有具名執行個體時。

IOptionsSnapshot<TOptions> 在應該於收到每個要求時重新計算選項的案例中很實用用。 如需詳細資訊,請參閱使用 IOptionsSnapshot 重新載入設定資料一節。

IOptions<TOptions> 可用於支援選項。 不過,IOptions<TOptions> 不支援前面的 IOptionsMonitor<TOptions> 案例。 您可以在現有架構與程式庫中繼續使用 IOptions<TOptions>,此程式庫已使用 IOptions<TOptions> 介面且不需要 IOptionsMonitor<TOptions> 提供的案例。

一般選項設定

一般選項設定是以範例應用程式中的範例 1 來示範。

選項類別必須為非抽象,且具有公用的無參數建構函式。 下列 MyOptions 類別有兩個屬性,Option1Option2。 設定預設值為選擇性,但在下列範例中,類別建構函式會設定 Option1 的預設值。 Option2 的預設值直接藉由初始化屬性來設定 (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 新增到服務容器,並繫結到設定:

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

下列頁面模型使用 建構函式相依性插入搭配 IOptionsMonitor<TOptions> 來存取設定 (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

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

當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:

option1 = value1_from_json, option2 = -1

注意

使用自訂 ConfigurationBuilder 從設定檔載入選項設定時,請確認已正確設定基底路徑:

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

services.Configure<MyOptions>(config);

透過 CreateDefaultBuilder 從設定檔載入選項設定時,不需要明確設定基底路徑。

使用委派設定簡單的選項

使用委派設定簡單的選項是以範例應用程式中的範例 2 來示範。

使用委派來設定選項值。 範例應用程式使用 MyOptionsWithDelegateConfig 類別 (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> 服務新增至服務容器。 它使用委派,以 MyOptionsWithDelegateConfig 設定繫結:

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

的索引。 .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}";

您可以新增多個設定提供者。 設定提供者可在 NuGet 套件中找到,而且會依註冊順序套用。 如需詳細資訊,請參閱ASP.NET Core 的設定

每次呼叫 Configure 時都會新增 IConfigureOptions<TOptions> 服務到服務容器。 在上述範例中,和的值 Option1Option2 是指定于中 appsettings.json ,但是和的值 Option1 Option2 會由設定的委派覆寫。

啟用多個設定服務時,最後一個指定的設定來源會「勝出」並設定此組態值。 當應用程式執行時,頁面模型的 OnGet 方法會傳回字串,顯示選項類別值:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

子選項組態

子選項組態是以範例應用程式中的範例 3 來示範。

應用程式應該建立屬於應用程式中特定案例群組 (類別) 的選項類別。 需要組態值的應用程式組件應該只能存取它們使用的設定值。

將選項繫結至組態時,選項類型中的每一個屬性都會繫結至 property[:sub-property:] 格式的組態索引鍵。 例如, MyOptions.Option1 屬性會系結至索引鍵,這個索引鍵 Option1 是從的 option1 屬性中讀取的 appsettings.json

在下列程式碼中,第三個 IConfigureOptions<TOptions> 服務新增至服務容器。 它會系結至檔案的 MySubOptions 區段 subsection appsettings.json

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

GetSection方法需要 Microsoft.Extensions.Configuration 命名空間。

範例的檔案會 appsettings.json 定義 subsection 具有和之索引鍵的成員 suboption1 suboption2

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

MySubOptions 類別會定義屬性 SubOption1SubOption2,來保存選項值 (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) 的字串:

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 方法會傳回字串,顯示子選項類別值:

subOption1 = subvalue1_from_json, subOption2 = 200

檢視模型提供的選項或使用直接檢視插入提供的選項

檢視模型提供的選項或使用直接檢視插入提供的選項是以範例應用程式中的範例 4 來示範。

可以在檢視模型中提供選項,或藉由將 IOptionsMonitor<TOptions> 直接插入至檢視來提供選項 (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>

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

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

執行應用程式時,轉譯的頁面中會顯示選項值:

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

使用 IOptionsSnapshot 重新載入設定資料

使用範例 IOptionsSnapshot<TOptions> 應用程式中的範例5示範重載設定資料。

IOptionsSnapshot<TOptions> 支援以最小的處理負擔來重新載入選項。

在要求的存留期內存取及快取選項時,會針對每個要求計算一次選項。

下列範例示範如何在 IOptionsSnapshot<TOptions> appsettings.json 變更 (頁面/索引) 之後建立新的。 伺服器的多個要求會傳回檔案所提供的常數值 appsettings.json ,直到檔案變更和設定重載為止。

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

snapshot option1 = value1_from_json, snapshot option2 = -1

將檔案中的值變更 appsettings.jsonvalue1_from_json UPDATED200 。 儲存 appsettings.json 檔案。 重新整理瀏覽器,以查看選項值更新:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

IConfigureNamedOptions 的具名選項支援

IConfigureNamedOptions<TOptions> 的具名選項支援是以範例應用程式中的範例 6 來示範。

「具名選項」支援可讓應用程式區別具名選項組態。 在範例應用程式中,命名選項是使用 OptionsServiceCollectionExtensions.Configu) 來宣告,而這會呼叫 >configurenamedoptions <TOptions> 。設定 擴充方法。 命名選項會區分大小寫。

// 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) 來存取具名選項:

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

執行範例應用程式後,會傳回具名選項:

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_2 值是由以下提供:

  • ConfigureServicesOption1named_options_2 委派。
  • MyOptions 類別所提供的 Option2 預設值。

使用 ConfigureAll 方法設定所有選項

使用 ConfigureAll 方法設定所有選項執行個體。 下列程式碼會為具有共通值的所有設定執行個體設定 Option1。 將下列程式碼手動新增至 Startup.ConfigureServices 方法:

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

新增程式碼之後執行範例應用程式,就會產生下列結果:

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

注意

所有選項都是具名執行個體。 現有的 IConfigureOptions<TOptions> 執行個體會視為以 Options.DefaultName 執行個體為目標,也就是 string.EmptyIConfigureNamedOptions<TOptions> 也會實作 IConfigureOptions<TOptions>IOptionsFactory<TOptions> 的預設實作有邏輯可以適當地使用每個項目。 null 具名選項用來以所有具名執行個體為目標,而不是特定的具名執行個體 (ConfigureAllPostConfigureAll 使用此慣例)。

OptionsBuilder API

OptionsBuilder<TOptions> 會用於設定 TOptions 執行個體。 因為 OptionsBuilder 僅為初始 AddOptions<TOptions>(string optionsName) 呼叫的單一參數,而不是出現在所有後續呼叫的參數,所以其可簡化建立具名選項的程序。 選項驗證及接受服務依存性的 ConfigureOptions 多載,只可透過 OptionsBuilder 使用。

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

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

使用 DI 服務來設定選項

在以下列兩種方式設定選項的同時,您可以從相依性插入中存取其他服務:

我們建議您將設定委派傳遞到 Configure,因為建立服務更複雜。 建立您自己的類型相當於,當您使用 Configure 時此架構可為您執行的動作。 呼叫 Configure 會註冊暫時性泛型 IConfigureNamedOptions<TOptions>,其具有會接受所指定泛型服務類型的建構函式。

選項設定後作業

使用 IPostConfigureOptions<TOptions> 來設定設定後作業。 設定後作業會在所有 IConfigureOptions<TOptions> 設定發生後執行:

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

PostConfigure 可用來後置設定具名選項:

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

使用 PostConfigureAll 後置設定所有設定執行個體:

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

在啟動期間存取選項

IOptions<TOptions>IOptionsMonitor<TOptions> 可用於 Startup.Configure,因為服務是在 Configure 方法執行之前建置。

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

請勿在 Startup.ConfigureServices 中使用 IOptions<TOptions>IOptionsMonitor<TOptions>。 可能會因為服務註冊的順序而有不一致的選項狀態存在。

其他資源