一, 前言
选项 (Options) 模式是对配置 (Configuration) 的功能的延伸. 在 12 章 (ASP.NET Core 中的配置二)Configuration 中有介绍过该功能(绑定到实体类, 绑定至对象图, 将数组绑定至类) 而选项模式又有个选项类(TOptions), 该选项类作用是指: 把选项类中的属性与配置来源中的键关联起来. 举个例, 假设 JSON 文件有个 Option1 键, 选项类中也有个叫 Option1 的属性名, 经过选项配置, 这样就能把 JSON 中的键的值映射到选项类属性值中. 也可以理解在项目应用中, 把一个 JSON 文件序列化到. net 类.
二, 常规选项配置
选项类必须为包含公共无参数构造函数的非抽象类. 在 appsettings.JSON 文件中添加 option1,option2,subsection 的配置:
- {
- "option1": "value1_from_json",
- "option2": -1,
- "subsection": {
- "suboption1": "subvalue1_from_json",
- "suboption2": 200
- },
- "Logging": {
- "LogLevel": {
- "Default": "Warning"
- }
- },
- "AllowedHosts": "*"
- }
新建 MyOptions 类(Models/MyOptions.cs), 以下类 MyOptions 具有三种属性: Option1 和 Option2. 设置默认值为可选, 但以下示例中的类构造函数设置了 Option1 的默认值. Option2 具有通过直接初始化属性设置的默认值:
- 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 添加到服务容器并绑定到配置:
- public void ConfigureServices(IServiceCollection services)
- {
- // Example #1: General configuration
- // Register the Configuration instance which MyOptions binds against.
- services.Configure<MyOptions>(Configuration);
- }
也可以使用自定义 ConfigurationBuilder 从设置文件加载选项配置时, 确认基路径设置正确, 添加到服务容器并绑定到配置:
- var configBuilder = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
- .AddJsonFile("appsettings.json", optional: true);
- var config = configBuilder.Build();
- services.Configure<MyOptions>(config);
以下页面模型通过 IOptionsMonitor<TOptions > 使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs):
- public class IndexModel
- {
- public IndexModel(IOptionsMonitor<MyOptions> optionsAccessor)
- {
- _options = optionsAccessor.CurrentValue;
- }
- private readonly MyOptions _options;
- public void OnGet()
- {
- // Example #1: Simple options
- var option1 = _options.Option1;
- var option2 = _options.Option2;
- var simpleOptions = $"option1 = {option1}, option2 = {option2}";
- }
- }
在 Home/Index 控制器 Action 下调用 IndexModel.OnGet 方法返回包含选项值的字符串:
- public HomeController(IOptionsMonitor<MyOptions> optionsAccessor)
- {
- _optionsAccessor = optionsAccessor;
- }
- private readonly IOptionsMonitor<MyOptions> _optionsAccessor;
- public IActionResult Index()
- {
- IndexModel indexModel = new IndexModel(_optionsAccessor);
- indexModel.OnGet();
- return View();
- }
三, 通过委托配置简单选项
使用委托设置选项值. 此示例应用程序使用新建 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 使用委托来配置绑定:
- public void ConfigureServices(IServiceCollection services)
- {
- // Example #2: Options bound and configured by a delegate
- services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
- {
- myOptions.Option1 = "value1_configured_by_delegate";
- myOptions.Option2 = 500;
- });
- }
以下页面模型通过 IOptionsMonitor<TOptions > 使用构造函数依赖关系注入来访问设置 (Pages/Index.cshtml.cs):
- public class IndexModel
- {
- private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
- public IndexModel(IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig)
- {
- _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
- }
- public void OnGet()
- {
- // Example #2: Options configured by delegate
- var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
- var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
- var simpleOptionsWithDelegateConfig =
- $"delegate_option1 = {delegate_config_option1}," +
- $"delegate_option2 = {delegate_config_option2}";
- }
- }
在 Home/Index 控制器 Action 下调用 IndexModel.OnGet 方法返回包含选项值的字符串:
- public HomeController(IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig)
- {
- _optionsAccessorWithDelegateConfig = optionsAccessorWithDelegateConfig;
- }
- private readonly IOptionsMonitor<MyOptionsWithDelegateConfig> _optionsAccessorWithDelegateConfig;
- public IActionResult Index()
- {
- IndexModel indexModel = new IndexModel(_optionsAccessorWithDelegateConfig);
- indexModel.OnGet();
- return View();
- }
每次调用 Configure 都会将 IConfigureOptions<TOptions > 服务添加到服务容器. 在前面的示例中, Option1 和 Option2 的值同时在 appsettings.JSON 中指定, 但 Option1 和 Option2 的值被配置的委托替代. 当启用多个配置服务时, 指定的最后一个配置源优于其他源, 由其设置配置值. 运行应用程序时, 页面模型的 OnGet 方法返回显示选项类值的字符串.
四, 子选项配置
将选项绑定到配置时, 选项类型中的每个属性都将绑定到窗体 property[:sub-property:]的配置键. 例如, MyOptions.Option1 属性将绑定到从 appsettings.JSON 中的 option1 属性读取的键 Option1. 在以下代码中, 已向服务容器添加 IConfigureOptions<TOptions > 服务. 它将 MySubOptions 绑定到 appsettings.JSON 文件的 subsection 部分:
- public void ConfigureServices(IServiceCollection services)
- {
- // Example #3: Suboptions
- // Bind options using a sub-section of the appsettings.JSON file.
- services.Configure<MySubOptions>(Configuration.GetSection("subsection"));
- }
新建 MySubOptions 类 (Models/MySubOptions.cs) 将属性 SubOption1 和 SubOption2 定义为保留选项值:
- public class MySubOptions
- {
- public MySubOptions()
- {
- // Set default values.
- SubOption1 = "value1_from_ctor";
- SubOption2 = 5;
- }
- public string SubOption1 { get; set; }
- public int SubOption2 { get; set; }
- }
以下页面模型通过 IOptionsMonitor<TOptions > 使用构造函数依赖关系注入来访问设置(Pages/Index.cshtml.cs):
- public class IndexModel
- {
- private readonly MySubOptions _subOptions;
- public IndexModel(IOptionsMonitor<MySubOptions> subOptionsAccessor)
- {
- _subOptions = subOptionsAccessor.CurrentValue;
- }
- public void OnGet()
- {
- // Example #3: Suboptions
- var subOption1 = _subOptions.SubOption1;
- var subOption2 = _subOptions.SubOption2;
- var subOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";
- }
- }
在 Home/Index 控制器 Action 下调用 IndexModel.OnGet 方法返回包含选项值的字符串:
- public HomeController(IOptionsMonitor<MySubOptions> subOptionsAccessor)
- {
- _subOptionsAccessor = subOptionsAccessor;
- }
- private readonly IOptionsMonitor<MySubOptions> _subOptionsAccessor;
- public IActionResult Index()
- {
- IndexModel indexModel = new IndexModel(_subOptionsAccessor);
- indexModel.OnGet();
- return View();
- }
五, 通过 IOptionsSnapshot 重新加载配置数据
IOptionsSnapshot 针对请求生命周期访问和缓存选项时, 每个请求只能计算一次选项. 以下示例演示如何在更改 appsettings.JSON(Pages/Index.cshtml.cs)后创建新的 IOptionsSnapshot<TOptions>. 在更改 appsettings.JSON 文件和重新加载配置之前, 针对服务器的多个请求返回 appsettings.JSON 文件提供的配置键值.
- public class IndexModel
- {
- private readonly MyOptions _snapshotOptions;
- public IndexModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
- {
- _snapshotOptions = snapshotOptionsAccessor.Value;
- }
- public void OnGet()
- {
- // Example #5: Snapshot options
- var snapshotOption1 = _snapshotOptions.Option1;
- var snapshotOption2 = _snapshotOptions.Option2;
- var snapshotOptions = $"snapshot option1 = {snapshotOption1}," + $"snapshot option2 = {snapshotOption2}";
- }
- }
下面显示从 appsettings.JSON 文件加载的初始 option1 和 option2 值:
snapshot option1 = value1_from_json, snapshot option2 = -1
将 appsettings.JSON 文件中的值更改为 value1_from_json UPDATED 和 200. 保存 appsettings.JSON 文件. 刷新浏览器, 查看更新的选项值:
snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200
六, 包含 IConfigureNamedOptions 的命名选项支持
命名选项支持允许应用程序在命名选项配置之间进行区分. 命名选项通过 OptionsServiceCollectionExtensions.Configure 进行声明, 其调用扩展方法 ConfigureNamedOptions<TOptions>.Configure:
- public void ConfigureServices(IServiceCollection services)
- {
- // 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";
- });
- }
通过 OnGet(Pages/Index.cshtml.cs)访问命名选项:
- public class IndexModel
- {
- private readonly MyOptions _named_options_1;
- private readonly MyOptions _named_options_2;
- public IndexModel(IOptionsSnapshot<MyOptions> namedOptionsAccessor)
- {
- _named_options_1 = namedOptionsAccessor.Get("named_options_1");
- _named_options_2 = namedOptionsAccessor.Get("named_options_2");
- }
- public void OnGet()
- {
- // 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}";
- var namedOptions = $"{named_options_1} {named_options_2}";
- }
- }
在 Home/Index 控制器 Action 下调用 IndexModel.OnGet 方法返回包含选项值的字符串:
- public HomeController(IOptionsSnapshot<MyOptions> namedOptionsAccessor)
- {
- _namedOptionsAccessor = namedOptionsAccessor;
- }
- private readonly IOptionsSnapshot<MyOptions> _namedOptionsAccessor;
- public IActionResult Index()
- {
- IndexModel indexModel = new IndexModel(_namedOptionsAccessor);
- indexModel.OnGet();
- return View();
- }
七, 使用 ConfigureAll 方法配置所有选项
使用 ConfigureAll 方法可以配置所有选项实例. 以下代码将针对包含公共值的所有配置实例配置 Option1. 将以下代码手动添加到 Startup.ConfigureServices 方法:
- services.ConfigureAll<MyOptions>(myOptions =>
- {
- myOptions.Option1 = "ConfigureAll replacement value";
- });
在 Home/Index 控制器 Action 下调用 IndexModel.OnGet 方法返回包含选项值的字符串:
参考资料: https://www.cnblogs.com/lonelyxmas/p/10302449.html
Net core 学习系列(十)--Net Core 配置
来源: http://www.bubuko.com/infodetail-3195806.html