Asp.Net Core 中的 Options
原文地址: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0
配置类设计软件工程原则:封装(配置类只依赖与之相关的配置)与隔离(配置类互不依赖)
Options 接口
- IOptions<TOptions>:
- IOptionsSnapshot<TOptions>: scoped 设计用于被transient 和 scoped 的类依赖
- IOptionsMonitor<TOptions>: singleton 设计用于对被单例的类依赖
- IOptionsFactory<TOptions>:
- IConfigureOptions<TOptions>
- IPostConfigureOptions<TOptions>
- IConfigureNamedOptions<TOptions>
- IOptionsMonitorCache
- IOptionsMonitor<TOptions>
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
public class PositionOptions //非抽象类,且必须有无参构造函数
{
public const string Position = "Position"; //field 不绑定
public string Title { get; set; } // property + read-write + public 绑定
public string Name { get; set; }
}
绑定方式 1 : 读取最新的配置信息
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions); //Configuration is ICongiruation
绑定方式 2: 读取最新的配置信息
var positionOptions = Configuration.GetSection(PositionOptions.Position).Get<PositionOptions>();
绑定方式 3:读取一开始的配置信息
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(PositionOptions.Position));
}
public class Test2Model : PageModel
{
private readonly PositionOptions _options;
public Test2Model(IOptions<PositionOptions> options)
{
_options = options.Value;
}
}
绑定方式 4:读取最新的配置信息,scoped 生命周期
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}
public class TestSnapModel : PageModel
{
private readonly MyOptions _snapshotOptions;
public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
{
_snapshotOptions = snapshotOptionsAccessor.Value;
}
}
绑定方式 5:读取最新的配置信息
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}
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}");
}
}
绑定方式 6:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
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"));
}
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);
}
}
所有选项都是命名实例。 IConfigureOptions<TOptions> 实例将被视为面向 Options.DefaultName 实例,即 string.Empty。
依赖注入
方法 1(绑定方式 7)
services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
方法 2 (绑定方式 8)
public class OptionsA: IConfigureOptions<TOptions>{}
service.Add<IConfigureOptions<TOptions>, OptionsA>();
public class OptionsB: IConfigureNamedOptions<TOptions>{}
service.Add<IConfigureNamedOptions<TOptions>, OptionsB>();
validation 验证
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
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; }
}
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.");
class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
public ValidateOptionsResult Validate(string name, MyConfigOptions options){}
}
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
PostConfiguration
services.PostConfigure<MyOptions>(myOptions => //default name instances
{
myOptions.Option1 = "post_configured_option1_value";
});
services.PostConfigure<MyOptions>("named_options_1", myOptions => //named instances
{
myOptions.Option1 = "post_configured_option1_value";
});
services.PostConfigureAll<MyOptions>(myOptions => //all instances
{
myOptions.Option1 = "post_configured_option1_value";
});
启动时获取配置值
IOptions<TOptions> and IOptionsMonitor<TOptions> 都可用于Configure 方法, 但是不可用于 ConfigureServices
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
{
var option1 = optionsAccessor.CurrentValue.Option1;
}