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); } }
使用 DI 服务配置选项
在配置选项时,可以通过以下两种方式通过依赖关系注入访问服务:
将配置委托传递给 OptionsBuilder 上的 Configure
services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
创建实现 IConfigureOptions 或 IConfigureNamedOptions 的类型,并将该类型注册为服务
建议将配置委托传递给 Configure,因为创建服务较复杂。 在调用 Configure 时,创建类型等效于框架执行的操作。 调用 Configure 会注册临时泛型 IConfigureNamedOptions,它具有接受指定的泛型服务类型的构造函数。
选项验证
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; } }
启用DataAnnotations验证
public void ConfigureServices(IServiceCollection services) { services.AddOptions<MyConfigOptions>() .Bind(Configuration.GetSection(MyConfigOptions.MyConfig)) .ValidateDataAnnotations(); services.AddControllersWithViews(); }
使用IValidateOptions更复杂的配置
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 设置后期配置。进行所有 IConfigureOptions 配置后运行后期配置
services.PostConfigure<MyOptions>(myOptions => { myOptions.Option1 = "post_configured_option1_value"; });
使用 PostConfigureAll 对所有配置实例进行后期配置
在启动期间访问选项
IOptions 和 IOptionsMonitor 可用于 Startup.Configure 中,因为在 Configure 方法执行之前已生成服务。
public void Configure(IApplicationBuilder app, IOptionsMonitor<MyOptions> optionsAccessor) { var option1 = optionsAccessor.CurrentValue.Option1; }
结论
IOptions<>是单例,因此一旦生成了,除非通过代码的方式更改,它的值是不会更新的。
IOptionsMonitor<>也是单例,但是它通过IOptionsChangeTokenSource<> 能够和配置文件一起更新,也能通过代码的方式更改值。