ASP.NET Core - 选项系统之源码介绍

.NET Core 选项系统的主要实现在 Microsoft.Extensions.Options 和 Microsoft.Extensions.Options.ConfigurationExtensions 两个 Nuget 包。对于一个框架的源码进行解读,我们可以从我们常用的框架中的类或方法入手,这些类或方法就是我们解读的入口。

从上面对选项系统的介绍中,大家也可以看出,日常对选项系统的使用涉及到的主要有 Configure 方法,有 IOptions<TOptions>IOptionsSnapshot<TOptions>IOptionMonitor<TOptions> 等接口。

Configure

首先看选项注册,也就是 Configure 方法,注册相关的方法都是扩展方法,之前的章节也讲到 Configure 方法有多个扩展来源,其中最常用的是 OptionsConfigurationServiceCollectionExtensions 中的 Configure 方法,该方法用于从配置信息中读取配置并绑定为选项,如下,这里将相应的方法单独摘出来了。

public static class OptionsConfigurationServiceCollectionExtensions
{
   
	/// <summary>
	/// Registers a configuration instance which TOptions will bind against.
	/// </summary>
	/// <typeparam name="TOptions">The type of options being configured.</typeparam>
	/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
	/// <param name="config">The configuration being bound.</param>
	/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
	[RequiresUnreferencedCode(OptionsBuilderConfigurationExtensions.TrimmingRequiredUnreferencedCodeMessage)]
	public static IServiceCollection Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IServiceCollection services, IConfiguration config) where TOptions : class
		=> services.Configure<TOptions>(Options.Options.DefaultName, config);

	/// <summary>
	/// Registers a configuration instance which TOptions will bind against.
	/// </summary>
	/// <typeparam name="TOptions">The type of options being configured.</typeparam>
	/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
	/// <param name="name">The name of the options instance.</param>
	/// <param name="config">The configuration being bound.</param>
	/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
	[RequiresUnreferencedCode(OptionsBuilderConfigurationExtensions.TrimmingRequiredUnreferencedCodeMessage)]
	public static IServiceCollection Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IServiceCollection services, string name, IConfiguration config) where TOptions : class
		=> services.Configure<TOptions>(name, config, _ => {
    });

	/// <summary>
	/// Registers a configuration instance which TOptions will bind against.
	/// </summary>
	/// <typeparam name="TOptions">The type of options being configured.</typeparam>
	/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
	/// <param name="config">The configuration being bound.</param>
	/// <param name="configureBinder">Used to configure the <see cref="BinderOptions"/>.</param>
	/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
	[RequiresUnreferencedCode(OptionsBuilderConfigurationExtensions.TrimmingRequiredUnreferencedCodeMessage)]
	public static IServiceCollection Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IServiceCollection services, IConfiguration config, Action<BinderOptions> configureBinder)
		where TOptions : class
		=> services.Configure<TOptions>(Options.Options.DefaultName, config, configureBinder);

	/// <summary>
	/// Registers a configuration instance which TOptions will bind against.
	/// </summary>
	/// <typeparam name="TOptions">The type of options being configured.</typeparam>
	/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
	/// <param name="name">The name of the options instance.</param>
	/// <param name="config">The configuration being bound.</param>
	/// <param name="configureBinder">Used to configure the <see cref="BinderOptions"/>.</param>
	/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
	[RequiresUnreferencedCode(OptionsBuilderConfigurationExtensions.TrimmingRequiredUnreferencedCodeMessage)]
	public static IServiceCollection Configure<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TOptions>(this IServiceCollection services, string name, IConfiguration config, Action<BinderOptions> configureBinder)
		where TOptions : class
	{
   
		if (services == null)
		{
   
			throw new ArgumentNullException(nameof(services));
		}

		if (config == null)
		{
   
			throw new ArgumentNullException(nameof(config));
		}

		services.AddOptions();
		services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config));
		return services.AddSingleton<IConfigureOptions<TOptions>>(new NamedConfigureFromConfigurationOptions<TOptions>(name, config, configureBinder));
	}
}

其中 IOptionsChangeTokenSource<TOptions> 接口是用来监听配置变化的服务,这个后面讲。

另外还有 OptionsServiceCollectionExtensions 中的 Configure 方法,用于直接通过委托对选项类进行配置。

public static class OptionsServiceCollectionExtensions
{
   

	public static IServiceCollection Configure<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class
		=> services.Configure(Options.Options.DefaultName, configureOptions);

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

可以看出,其实选项系统中的选项都是命名模式的,默认名称为 Options.Options.DefaultName,实际就是 string.Empty。当我们调用 Configure 方法对选项进行配置的时候,实际上时调用了 AddOptions 方法,并且往容器中添加了一个单例的实现了 IConfigureOptions<TOptions> 接口的实现。

IConfigureOptions、IConfigureNamedOptions、IPostConfigureOptions

其中 IConfigureOptions<TOptions> 是选项配置行为服务接口,ConfigureOptions<TOptions> 是它的默认实现,该类的内容很简单,它的内部主要就是保存了一个委托,用于记录使用者对选项的配置操作。

public class ConfigureOptions<TOptions> : IConfigureOptions<TOptions> where TOptions : class
{
   
	/// <summary>
	/// Constructor.
	/// </summary>
	/// <param name="action">The action to register.</param>
	public ConfigureOptions(Action<TOptions> action
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值