.Net 5 Options 选项
DotNet Configuration 源码:https://github.com/dotnet/runtime/tree/master/src/libraries/,其中以 Microsoft.Extensions.Options 开头的项目
Options 官方文档:
- https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0
- https://docs.microsoft.com/en-us/dotnet/core/extensions/options
Nuget包:Microsoft.Extensions.Options
建议先掌握:
- DependencyInjection ( 依赖注入 ):
- Configuration ( 配置 ) :
介绍
Options
提供了对配置数据的强类型访问
Options
提供了验证选项的机制
Configure
首先声明一个选项类
public class MyOption
{
public string A { get; set; }
public string B { get; set; }
}
使用Configure
扩展方法对选项类进行配置
var serviceCollection = new ServiceCollection();
// 配置 MyOption
serviceCollection.Configure<MyOption>(n =>
{
n.A = "A Value";
n.B = "B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
获取IOptions<MyOption>
选项服务
var myOption = serviceProvider.GetRequiredService<IOptions<MyOption>>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
在http://Aps.Net 中使用
配置
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure<MyOption>(option =>
{
option.A = "A Value";
option.B = "A Value";
});
}
注入Ioption<MyOption>
[Route("Home")]
public class HomeController : ControllerBase
{
private readonly MyOption _myOption;
public HomeController(IOptions<MyOption> myOptions)
{
_myOption = myOptions.Value;
}
[HttpGet]
public string GetAsync()
{
return $"A:{_myOption.A},B:{_myOption.B}";
}
}
绑定配置,使用IConfiguration
来配置选项
Nuget包:Microsoft.Extensions.Options.ConfigurationExtensions
Configure<TOptions>(IConfigureation configuration)
不仅仅会绑定配置,还会添加对配置文件的更改通知,通知IOptionsMonitor
重新计算选项
实例:
appsettings.json
{
"MySetting": {
"A": "A Value",
"B": "B Value"
}
}
C#
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.Configure<MyOption>(configuration.GetSection("MySetting"));
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService<IOptions<MyOption>>();
var myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
PostConfigure
PostConfigure
会在 Configure
之后进行配置
实例:
var serviceCollection = new ServiceCollection();
serviceCollection.PostConfigure<MyOption>(option =>
{
option.B = "PostConfigure B Value";
});
serviceCollection.Configure<MyOption>(n =>
{
n.A = "A Value";
n.B = "B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService<IOptions<MyOption>>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value
Console.WriteLine(myOptionValue.B); // PostConfigure B Value
命名选项
可以给选项命名
默认选项名称为空字符串
IOptions
不支持获取命名选项,只能获取默认命名选项
可以使用IOptionsSnapshot
、IOptionsMonitor
等获取命名选项
IOptionsSnapshot
继承子IOptions
并添加了Get(string optionName)
方法来获取命名选项
IOptionsMonitor
的CurrentValue
属性用于获取默认选项,Get(string optionName)
方法来获取命名选项
实例:
var serviceCollection = new ServiceCollection();
// 配置 MyOption
serviceCollection.Configure<MyOption>(n =>
{
n.A = "A Value";
n.B = "B Value";
});
serviceCollection.Configure<MyOption>("My", n =>
{
n.A = "My:A Value";
n.B = "My:B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService<IOptions<MyOption>>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value
Console.WriteLine(myOptionValue.B); // B Value
// IOptionsSnapshot 获取命名选项
var myOption2 = serviceProvider.GetRequiredService<IOptionsSnapshot<MyOption>>();
MyOption myOptionValue2 = myOption2.Get("My");
Console.WriteLine(myOptionValue2.A); // My:A Value
Console.WriteLine(myOptionValue2.B); // My:B Value
// IOptionsMonitor 获取命名选项
var myOptionsMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<MyOption>>();
MyOption myOptionValue3 = myOptionsMonitor.Get("My");
Console.WriteLine(myOptionValue3.A);
Console.WriteLine(myOptionValue3.B);
ConfigureAll、PostConfigureAll
ConfigureAll
、PostConfigureAll
可以配置全部的命名配置
实例:
var serviceCollection = new ServiceCollection();
serviceCollection.ConfigureAll<MyOption>(n =>
{
n.A = "A Value,Config By ConfigureAll";
});
// 配置 MyOption
serviceCollection.Configure<MyOption>(n =>
{
n.B = "B Value";
});
serviceCollection.Configure<MyOption>("My", n =>
{
n.B = "My:B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService<IOptions<MyOption>>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value,Config By ConfigureAll
Console.WriteLine(myOptionValue.B); // B Value
var myOption2 = serviceProvider.GetRequiredService<IOptionsSnapshot<MyOption>>();
MyOption myOptionValue2 = myOption2.Get("My");
Console.WriteLine(myOptionValue2.A); // A Value,Config By ConfigureAll
Console.WriteLine(myOptionValue2.B); // My:B Value
IOptions、IOptionsSnapshot、IOptionsMonitor
IOptions<TOptions>
- 只会计算一次选项
- 不支持命名选项
- 单例服务,可以注入到任何服务生存期
IOptionsSnapshot<TOptions>
- 会计算多次选项,每次请求时应重新计算选项
- 注册为范围内,因此无法注入到单一实例服务
- 支持命名选项
IOptionsMonitor<TOptions>
:
- 单例服务,可以注入到任何服务生存期
- 支持更改通知 ( 比如配置文件更改通知 )
- 支持命名选项
- 支持重载配置
- 选择性选项失效 (IOptionsMonitorCache)
IOptionsFactory<TOptions>
负责创建、计算选项实例,IOptions<TOptions>
、IOptionsSnapshot<TOptions>
、IOptionsMonitor<TOptions>
都使用它来创建选项实例
对比实例:
appsettings.json
{
"MySetting": {
"B": "B 1"
}
}
C# Startup
public class Startup
{
public IConfiguration Configuration { get; }
public Startup( IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure<MyOption>(option => { option.A = DateTime.Now.ToString(CultureInfo.CurrentCulture); });
services.Configure<MyOption>(Configuration.GetSection("MySetting"));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(options => { options.MapControllers(); });
}
}
C# HomeController
[Route("Home")]
public class HomeController : ControllerBase
{
public IOptions<MyOption> MyOptions { get; }
public IOptionsSnapshot<MyOption> MyOptionsSnapshot { get; }
public IOptionsMonitor<MyOption> MyOptionsMonitor { get; }
public IServiceProvider ServiceProvider { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
public HomeController(
IOptions<MyOption> myOptions,
IOptionsSnapshot<MyOption> myOptionsSnapshot,
IOptionsMonitor<MyOption> myOptionsMonitor,
IServiceProvider serviceProvider,
IWebHostEnvironment webHostEnvironment
)
{
MyOptions = myOptions;
MyOptionsSnapshot = myOptionsSnapshot;
MyOptionsMonitor = myOptionsMonitor;
ServiceProvider = serviceProvider;
WebHostEnvironment = webHostEnvironment;
}
[HttpGet]
public string GetAsync()
{
Console.WriteLine($"MyOption A:{MyOptions.Value.A}");
Console.WriteLine($"MyOption B:{MyOptions.Value.B}");
Console.WriteLine($"MyOptionsSnapshot A:{MyOptionsSnapshot.Value.A}");
Console.WriteLine($"MyOptionsSnapshot B:{MyOptionsSnapshot.Value.B}");
Console.WriteLine($"MyOptionsMonitor A:{MyOptionsMonitor.CurrentValue.A}");
Console.WriteLine($"MyOptionsMonitor B:{MyOptionsMonitor.CurrentValue.B}");
// 更改appsetting配置文件,处罚文件更改通知 ( json文件配置需要开启更改重载 )
System.IO.File.WriteAllText(WebHostEnvironment.ContentRootPath + "/appsettings.json",
JsonSerializer.Serialize(new{
MySetting = new
{
B = "B 2"
}
})
);
var timer = new Timer(2000);
timer.Start();
timer.Elapsed += (sender, e) =>
{
Console.WriteLine($"MyOption2 A:{MyOptions.Value.A}");
Console.WriteLine($"MyOption2 B:{MyOptions.Value.B}");
Console.WriteLine($"MyOptionsSnapshot2 A:{MyOptionsSnapshot.Value.A}");
Console.WriteLine($"MyOptionsSnapshot2 B:{MyOptionsSnapshot.Value.B}");
Console.WriteLine($"MyOptionsMonitor2 A:{MyOptionsMonitor.CurrentValue.A}");
Console.WriteLine($"MyOptionsMonitor2 B:{MyOptionsMonitor.CurrentValue.B}");
timer.Stop();
};
return "Hello";
}