net core -Options
services.Configure<BookOptions>(Configuration.GetSection(BookOptions.Book));
builder.Services.AddOptions<Test>(builder.Configuration[""]); builder.Services.Configure<Test>(builder.Configuration.GetSection("")); // <---- add this line. builder.Configuration.GetSection("").Get<Test>();
基本使用
/* 这里是把整个委托传入的。需要的时候才会去执行。给相应属性赋值 services.AddOptions(); // 所有不用手动加这段代码 services.AddSingleton<IConfigureOptions<TOptions>>(new ConfigureNamedOptions<TOptions>(name, configureOptions)); */ builder.Services.Configure<EmailOption>(O=>O.Address=$"time:{DateTime.Now}");
看下源码:
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, Action<TOptions> configureOptions) where TOptions : class { ThrowHelper.ThrowIfNull(services); ThrowHelper.ThrowIfNull(configureOptions); services.AddOptions(); services.AddSingleton<IConfigureOptions<TOptions>>(new ConfigureNamedOptions<TOptions>(name, configureOptions)); return services; }
这里出现了一个 ConfigureNamedOptions:
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 (Name == null || name == Name) { Action?.Invoke(options); // 执行action委托给options实例赋值。 } } public void Configure(TOptions options) => Configure(Options.DefaultName, options); }
这里有个扩展点, 定义自己的configure。1 先定义自己的IConfigureNamedOptions:
public class ConfigurePublicSlackApiSettings: IConfigureNamedOptions<SlackApiSettings> { // inject the PublicSlackDetailsService directly private readonly PublicSlackDetailsService _service; public ConfigurePublicSlackApiSettings(PublicSlackDetailsService service) { _service = service; } public void Configure(string name, SlackApiSettings options) { if (name == "Public") { options.WebhookUrl = _service.GetPublicWebhookUrl(); } } public void Configure(SlackApiSettings options) => Configure(Options.DefaultName, options); }
2 添加自己的扩展方法
public static IServiceCollection ConfigureMy<TOptions>(this IServiceCollection services, string? name, Action<TOptions> configureOptions) where TOptions : class { services.AddOptions(); services.AddSingleton<IConfigureOptions<TOptions>>
(new ConfigurePublicSlackApiSettings<TOptions>(name, configureOptions)); return services;
}
回到上面,还有这种写法:
builder.Services.Configure<EmailOption>("", builder.Configuration.GetSection("Email"));
看下源码,其实处理方式都差不多,只是给EmailOption实例赋值的方式不一致而已。
public static IServiceCollection Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IServiceCollection services, string? name, IConfiguration config, Action<BinderOptions>? configureBinder) where TOptions : class { services.AddOptions(); services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config)); return services.AddSingleton<IConfigureOptions<TOptions>>(new NamedConfigureFromConfigurationOptions<TOptions>(name, config, configureBinder)); }
NamedConfigureFromConfigurationOptions这个类最后走的也是ConfigureNamedOptions<TOptions> 中action.Invoke方法。但传的Action是
options => config.Bind(options, configureBinder):
public NamedConfigureFromConfigurationOptions(string? name, IConfiguration config, Action<BinderOptions>? configureBinder) : base(name, options => config.Bind(options, configureBinder)) { ThrowHelper.ThrowIfNull(config); }
关于config.Bind(options, configureBinder)解析方式就用到 services.AddOptions();里注入的OptionsFactory.cs类,这个就不展开了。
public static IServiceCollection AddOptions(this IServiceCollection services) { services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(UnnamedOptionsManager<>))); 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; }