前言 ASP.NET Core 後我們的配置變得更加輕量級了,在ASP.NET Core中,配置模型得到了顯著的擴展和增強,應用程式配置可以存儲在多環境變數配置中,appsettings.json用戶機密等 並可以通過應用程式中的相同界面輕鬆訪問,除此之外,ASP.NET中的新配置系統允許使用Opt ...
前言
ASP.NET Core 後我們的配置變得更加輕量級了,在ASP.NET Core中,配置模型得到了顯著的擴展和增強,應用程式配置可以存儲在多環境變數配置中,appsettings.json用戶機密等 並可以通過應用程式中的相同界面輕鬆訪問,除此之外,ASP.NET中的新配置系統允許使用Options的強類型設置。
強類型Options
在ASP.NET Core中沒有AppSettings["Key"]預設方法,那麼推薦的是創建強類型的配置類,去綁定配置項。
public class MyOptions
{
public string Name { get; set; }
public string Url { get; set; }
}
然後我們在appsettings.json中添加如下內容:
{
"MyOptions":
{
"Name": "TestName",
"Url": "TestUrl"
}
}
配置綁定到類
ConfigureServices方法進行配置以綁定到類
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddControllers();
}
MyOptions只需將IOptions<>類的實例註入控制器中,然後通過Value屬性獲取Myoptions:
public class WeatherForecastController : ControllerBase
{
private readonly MyOptions _options;
public WeatherForecastController(IOptions<MyOptions> options)
{
_options = options.Value;
}
[HttpGet]
public OkObjectResult Get() {
return Ok(string.Format("Name:{0},Url:{1}", _options.Name,_options.Url));
}
}
Configure
委托配置
//基礎註冊方式
services.Configure<MyOptions>(o => { o.Url = "MyOptions"; o.Name = "Name111"; });
//指定具體名稱
services.Configure<MyOptions>("Option", o => { o.Url = "MyOptions"; o.Name = "Name111"; }) ;
//配置所有實例
services.ConfigureAll<MyOptions>(options =>{ options.Name = "Name1"; options.Url = "Url1";});
通過配置文件配置
// 使用配置文件來註冊實例
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
// 指定具體名稱
services.Configure<MyOptions>("Option", Configuration.GetSection("MyOptions"));
PostConfigure
PostConfigure會在Configure註冊完之後再進行註冊
services.PostConfigure<MyOptions>(o => o.Name = "Name1");
services.PostConfigure<MyOptions>("Option", o => o.Name = "Name1");
services.PostConfigureAll<MyOptions>(o => o.Name = "Name1");
源碼解析
IConfigureOptions介面
public interface IConfigureOptions<in TOptions> where TOptions : class
{
void Configure(TOptions options);
}
Configure為方便使用IConfigureOptions註冊單例ConfigureNamedOptions
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, Action<TOptions> configureOptions)
where TOptions : class
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (configureOptions == null)
{
throw new ArgumentNullException(nameof(configureOptions));
}
services.AddOptions();
services.AddSingleton<IConfigureOptions<TOptions>>(new ConfigureNamedOptions<TOptions>(name, configureOptions));
return services;
}
上面代碼IConfigureOptions實現了ConfigureNamedOptions,那我們再來看看內部源碼
ConfigureNamedOptions 其實就是把我們註冊的Action包裝成統一的Configure方法,以方便後續創建Options實例時,進行初始化。
public class ConfigureNamedOptions<TOptions> : IConfigureNamedOptions<TOptions> where TOptions : class
{
public ConfigureNamedOptions(string name, Action<TOptions> action)
{
Name = name;
Action = action;
}
public string Name { get; }
public Action<TOptions> Action { get; }
public virtual void Configure(string name, TOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
// Null name is used to configure all named options.
if (Name == null || name == Name)
{
Action?.Invoke(options);
}
}
public void Configure(TOptions options) => Configure(Options.DefaultName, options);
}
在 services.Configure
public virtual void Configure(string name, TOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
// Null name is used to configure all named options.
if (Name == null || name == Name)
{
Action?.Invoke(options);
}
}
public void Configure(TOptions options) => Configure(Options.DefaultName, options);
預設使用的是Options.DefaultName
AddOptions預設方法預設為我們註冊了一些核心的類
public static IServiceCollection AddOptions(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));
services.TryAdd(ServiceDescriptor.Transient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>)));
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>)));
return services;
}