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;
}

 

posted @ 2023-06-02 17:10  vba是最好的语言  阅读(42)  评论(0编辑  收藏  举报