什么是选项
选项是 ASP.NET Core
推荐的动态读取配置的方式,这种方式将配置文件数据用一个强类型来托管,能够实现配置验证、默认值配置、实时读取等功能。
与配置的区别
选项实际上也是配置,但在后者的基础上添加了配置验证、默认值/后期配置设定及提供了多种接口读取配置信息,同时还支持供配置更改通知等强大灵活功能。
所以,除了一次性读取使用的配置以外,都应该选用 选项 替换 配置。
选项的使用
假设我们需要在系统运行时获取系统名称、版本号及版权信息,这些信息可能随时变化而且需要在多个地方使用。这时就需要将这些信息配置起来。具体步骤如下:
配置 appsettings.json
信息
{ "AppInfo": { "Name": "Furion", "Version": "1.0.0", "Company": "Baiqian" } }
创建 AppInfoOptions
强类型类
using Furion.ConfigurableOptions; namespace Furion.Application { public class AppInfoOptions : IConfigurableOptions { public string Name { get; set; } public string Version { get; set; } public string Company { get; set; } } }
注册 AppInfoOptions
服务
选项不同于配置,需在应用启动时注册
Furion.Web.Core\FurWebCoreStartup.cs using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; namespace Furion.Web.Core { [AppStartup(800)] public sealed class FurWebCoreStartup : AppStartup { public void ConfigureServices(IServiceCollection services) { services.AddConfigurableOptions<AppInfoOptions>(); } } }
读取 AppInfoOptions
信息
在 Furion
框架中,提供了多种读取方式:
- 通过
App.GetOptions<TOptions>(jsonKey)
读取(不推荐) - 通过依赖注入以下实例读取:
IOptions<TOptions>
IOptionsSnapshot<TOptions>
IOptionsMonitor<TOptions>
- 通过
App
静态类提供的静态方法获取:App.GetOptions<TOptions>()
App.GetOptionsMonitor<TOptions>()
App.GetOptionsSnapshot<TOptions>()
using Furion.Application; using Microsoft.AspNetCore.Mvc; namespace Furion.Web.Entry.Controllers { [Route("api/[controller]")] public class DefaultController : ControllerBase { [HttpGet] public string Get() { // 不推荐采用此方式读取 var appInfo = App.GetOptions<AppInfoOptions>("AppInfo"); return $@"名称:{appInfo.Name}, 版本:{appInfo.Version}, 公司:{appInfo.Company}"; } } }
Furion/App/App.cs using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Furion { /// <summary> /// 全局应用类 /// </summary> public static class App { /// <summary> /// 获取选项 /// </summary> /// <typeparam name="TOptions">强类型选项类</typeparam> /// <param name="jsonKey">配置中对应的Key</param> /// <returns></returns> public static TOptions GetOptions<TOptions>(string jsonKey) where TOptions : class => Configuration.GetSection(jsonKey).Get<TOptions>(); /// <summary> /// 获取选项 /// </summary> /// <typeparam name="TOptions">强类型选项类</typeparam> /// <returns></returns> public static TOptions GetOptions<TOptions>() where TOptions : class => ServiceProvider.GetService<IOptions<TOptions>>().Value; // Other Codes... } }
如何选择读取方式
- 如果选项需要在多个地方使用,则无论任何时候都不推荐使用
App.GetOptions<TOptions>(jsonKey)
- 在可依赖注入类中,依赖注入
IOptions[Snapshot|Monitor]<TOptions>
读取 - 在静态类/非依赖注入类中,选择
App.GetOptions[Snapshot|Monitor]<TOptions>()
读取
选项接口说明
ASP.NET Core
应用提供了多种读取选项的接口:
IOptions<TOptions>
:- 不支持:
- 在应用启动后读取配置数据
- 命名选项
- 注册为单一实例且可以注入到任何服务生存期
- 不支持:
IOptionsSnapshot<TOptions>
:- 在每次请求时应重新计算选项的方案中有用
- 注册为范围内,因此无法注入到单一实例服务
- 支持命名选项
IOptionsMonitor<TOptions>
:- 用于检索选项并管理 TOptions 实例的选项通知。
- 注册为单一实例且可以注入到任何服务生存期。
- 支持:
- 更改通知
- 命名选项
- 可重载配置
- 选择性选项失效
(IOptionsMonitorCache<TOptions>)
选项自定义配置
我们知道,选项实际上需要和配置文件特定键值挂钩,那 Furion
是如何准确的找到配置文件中的键值的呢?
选项查找键流程
- 没有贴
[OptionsSettings]
特性- 以
Options
结尾,则去除Options
字符串 - 否则返回
类名称
- 以
- 贴了
[OptionsSettings]
特性- 如果配置了
JsonKey
属性,则返回JsonKey
的值 - 否则返回
类名称
- 如果配置了
public class AppInfoOptions : IConfigurableOptions { public string Name { get; set; } public string Version { get; set; } public string Company { get; set; } }
- 不以
Options
结尾,则键名为:AppInfoSettings
public class AppInfoSettings : IConfigurableOptions { public string Name { get; set; } public string Version { get; set; } public string Company { get; set; } }
[OptionsSettings]
说明
选项类可以通过 [OptionsSettings]
来配置查找路径值。
选项验证
选项支持验证配置有效性,在 Furion
框架中,通过 services.AddConfigurableOptions<TOptions>()
注册选项默认启用了验证支持。
包括:
- 特性方式
DataAnnotations
- 自定义复杂验证
IValidateOptions<TOptions>
using Furion.ConfigurableOptions; using System.ComponentModel.DataAnnotations; namespace Furion.Application { public class AppInfoOptions : IConfigurableOptions { [Required(ErrorMessage = "名称不能为空")] public string Name { get; set; } [Required, RegularExpression(@"^[0-9][0-9\.]+[0-9]$", ErrorMessage = "不是有效的版本号")] public string Version { get; set; } [Required, MaxLength(100)] public string Company { get; set; } } }
选项后期配置
选项后期配置通俗一点来说,可以在运行时解析值或设定默认值/后期配置等。
在 Furion
框架中,配置选项后期配置很简单,只需要继承 IConfigurableOptions<TOptions>
接口并实现 PostConfigure(TOptions options)
方法。
using Furion.ConfigurableOptions; using Microsoft.Extensions.Configuration; using System.ComponentModel.DataAnnotations; namespace Furion.Application { public class AppInfoOptions : IConfigurableOptions<AppInfoOptions> { [Required(ErrorMessage = "名称不能为空")] public string Name { get; set; } [Required] public string Version { get; set; } [Required, MaxLength(100)] public string Company { get; set; } public void PostConfigure(AppInfoOptions options, IConfiguration configuration) { options.Name ??= "Furion"; options.Version ??= "1.0.0"; options.Company ??= "Baiqian"; } } }
选项更改通知(热更新
)
Furion
框架提供了非常简单且灵活的方式监听选项更改,也就是 appsettings.json
或 自定义配置文件发生任何更改都会触发处理方法。
使用非常简单,只需要继承 IConfigurableOptionsListener<TOptions>
接口并实现 void OnListener(TOptions options, IConfiguration configuration)
方法即可。
using Furion.ConfigurableOptions; namespace Furion.Application { public class AppInfoOptions : IConfigurableOptionsListener<AppInfoOptions> { public string Name { get; set; } public string Version { get; set; } public string Company { get; set; } } public void OnListener(AppInfoOptions options, IConfiguration configuration) { var name = options.Name; // 实时的最新值 var version = options.Version; // 实时的最新值 } public void PostConfigure(AppInfoOptions options, IConfiguration configuration) { } }
选项的优缺点
优点
- 强类型配置
- 提供多种读取方式
- 支持热加载
- 支持设置默认值/后期配置
- 支持在运行环境中动态配置
- 支持验证配置有效性
- 支持更改通知
- 支持命名选项
缺点
- 需要定义对应类型
- 需要在启动时注册