ASP.NET Core 選項模式原始碼學習Options Configure(一)
阿新 • • 發佈:2019-12-11
前言
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;
}