AspNetCore Options

前言

Options

1.基础知识

Options:

  • 依赖项

    Microsoft.Extensions.Options:选项的核心包,扩展IServiceCollection接口,只支持内存配置。

    Microsoft.Extensions.Options.ConfigurationExtensions:配置文件的扩展,支持IConfiguration进行配置。

    Microsoft.Extensions.DependencyInjection:选项必须配合容器使用

    Microsoft.Extensions.Options.DataAnnotations:支持数据注解验证

  • 核心接口

    IOptions:单实列,不支持命名。

    IOptionsSnapshot:每次实列化时更新选项,scope级别,支持命名配置

    IOptionsMonitor:监听配置更改并通知,Singleton级别,支持命名配置

    IOptionsFactory:管理Options实列,包括创建、配置、验证,支持命名配置

    IConfigureOptions:保存配置选项时的委托,一个选项可以添加多个委托进行配置

    IPostConfigureOptions:保存配置选项的委托,在IConfigureOptions委托执行之后执行

    OptionsChangeTokenSource:用于监听IConfiguration的更改通知

    IValidateOptions:配置选项之后的验证

2.基本使用

安装包:

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
  </ItemGroup>

代码:

image-20231113212931020

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
var services = new ServiceCollection();
// 第一种 通过委托来配置选项,同一个选项可以按顺序执行多个Configure。
services.Configure<TemCofig>(config =>
{
    config.Field1 = "11111";
});
// 第二种 在所有的Configure执行之后配置选项。同一个选项可以按顺序执行多个PostConfigure。
services.PostConfigure<TemCofig>(config =>
{
    config.Field2 = "22222";
});
// 第三种 AddOptions支持链式调用。本质还是执行Configure和PostConfigure
//services.AddOptions<TemCofig>()
//    .Configure(config => { config.Field1 = "33333"; })
//    .PostConfigure(postConfig => { postConfig.Field2 = "44444"; });

var sp = services.BuildServiceProvider();
//解析选项
var optionsFactory = sp.GetRequiredService<IOptionsFactory<TemCofig>>();
var options = sp.GetRequiredService<IOptions<TemCofig>>();
var optionsMonitor = sp.GetRequiredService<IOptionsMonitor<TemCofig>>();
var optionsSnapshot = sp.GetRequiredService<IOptionsSnapshot<TemCofig>>();

Console.WriteLine("Hello, World!");
Console.ReadKey();
public class TemCofig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

3.源码

1.调用Configure会向容器注册一个IConfigureOptions类型的服务,并且记录我们编写的委托

image-20231113201148248

2.调用PostConfigure会向容器注册一个IPostConfigureOptions类型的服务,并且记录我们编写的委托

image-20231113201228608

3.Configure或者PostConfigure都会执行AddOptions();

image-20231113201308059

image-20231113201331259

4.AddOptions();会尝试向容器注册IOptions、IOptionsSnapshot、IOptionsMonitor、IOptionsFactory、IOptionsMonitorCache

image-20231113201344079

5.IOptionsFactory内部实现逻辑是,首先加载所有注册的IConfigureOptions、IPostConfigureOptions、IValidateOptions服务实列Create方法首先通过反射调用选项的无参数构造器来实列化选项。然后通过选项实列来执行所有IConfigureOptions中的委托,然后在执行所有IPostConfigureOptions中委托,然后在执行IValidateOptions中的验证逻辑。

image-20231113201626162

6.IOptions实列依赖IOptionsFactory创建一个名为Options.DefaultName的选项,由于是单实列的,只能执行一次委托来计算选项的值。

image-20231113202041350

image-20231113202024700

7.IOptionsSnapshot依赖IOptionsFactory创建一个名为Options.DefaultName的选项Value,并支持命名Get方法获取选项(内置缓存机制)因为是Scoped所以每次获取新的选项实列都会执行委托来重新计算选项值。

8.IOptionsMonitor依赖IOptionsFactory提供支持命名的Get方法获取选项,虽然IOptionsMonitor是单实列的并且会监听配置更改,可以通过注册OnChange来执行更改之后的逻辑来更新选项。

4.监听更改

IOptions:单实列,不支持命名。

IOptionsSnapshot:每次实列化时更新选项,scope级别,支持命名配置

IOptionsMonitor:监听配置更改并通知,Singleton级别,支持命名配置

安装包:

	<ItemGroup>
		<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
		<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
		<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
		<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="7.0.0" />
	</ItemGroup>

添加配置文件:

image-20231113214330092

{
  "TmpConfig": {
    "Field1": "123",
    "Field2": "456"
  }
}

代码:

reloadOnChange必须设置true

reloadOnChange:如果文件更改,是否应该重新加载配置。

image-20231113214544980

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

var configuration = new ConfigurationManager();
configuration.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("TmpConfig.json", optional: false, reloadOnChange: true);
var services = new ServiceCollection();
services.Configure<TmpConfig>(configuration.GetSection("TmpConfig"));
var container = services.BuildServiceProvider();
while (true)
{
    Thread.Sleep(2000);
    using (var scope = container.CreateScope())
    {
        var o1 = scope.ServiceProvider.GetRequiredService<IOptions<TmpConfig>>();
        var o2 = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<TmpConfig>>();
        var o3 = scope.ServiceProvider.GetRequiredService<IOptionsMonitor<TmpConfig>>();
        Console.WriteLine("==================");
        Console.WriteLine($"IOptions:{o1.Value.Field1}---{o1.Value.Field2}");
        // IOptionsSnapshot可以更改文件
        Console.WriteLine($"IOptionsSnapshot:{o2.Value.Field1}---{o2.Value.Field2}");
        Console.WriteLine($"IOptionsMonitor:{o3.CurrentValue.Field1}---{o3.CurrentValue.Field2}");
        // IOptionsMonitor可执行更改时发生事件
        o3.OnChange(o =>
        {
            Console.WriteLine("选项发生更改了");
        });
    }
}

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Console.ReadKey();
public class TmpConfig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

5.命名选项

安装包:

<ItemGroup>	
	<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
	<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />		
</ItemGroup>

Options.DefaultName默认string.Empty

image-20231113215602996

代码:

通过Get方法获取指定名称配置

image-20231113215726458

6.高级配置

安装包:

<ItemGroup>
	<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
	<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
</ItemGroup>

6.1DI配置

image-20231113220955687

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.VisualBasic;
using System.Runtime.Intrinsics.Arm;

var services = new ServiceCollection();
// 注册DI服务,只能是单实例
services.AddSingleton<TmpConfigConfigration>();
services.AddOptions<TmpConfig>()
    //.Configure(c => { c.Field1 = "33333"; c.Field2 = "44444"; })
    .PostConfigure<TmpConfigConfigration>((options, dep) =>
    {
        dep.Configure(options);
    });
var container = services.BuildServiceProvider();
var options = container.GetRequiredService<IOptions<TmpConfig>>();
Console.WriteLine("Hello, World!");
Console.ReadKey();
public class TmpConfig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

internal class TmpConfigConfigration
{
    public void Configure(TmpConfig config)
    {
        config.Field1 = "11111";
        config.Field2 = "22222";
    }
}

6.2IConfigureOptions

image-20231113222506369

var services = new ServiceCollection();
services.AddOptions();
services.AddSingleton<IConfigureOptions<TmpConfig>, TmpConfigConfigureOptions>();
var container = services.BuildServiceProvider();
var tmpConfigOptions = container.GetRequiredService<IOptions<TmpConfig>>();

public class TmpConfig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

internal class TmpConfigConfigureOptions : IConfigureOptions<TmpConfig>
{
    public void Configure(TmpConfig tmpConfig)
    {
        tmpConfig.Field1 = "11111";
        tmpConfig.Field2 = "22222";
    }
}

6.3IPostConfigureOptions

image-20231113222707845

var services = new ServiceCollection();
services.AddOptions();
services.AddSingleton<IPostConfigureOptions<TmpConfig>, TmpConfigPostConfigureOptions>();
var container = services.BuildServiceProvider();
var tmpConfigOptions = container.GetRequiredService<IOptions<TmpConfig>>();


public class TmpConfig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}
internal class TmpConfigPostConfigureOptions : IPostConfigureOptions<TmpConfig>
{

    public void PostConfigure(string? name, TmpConfig tmpConfig)
    {
        tmpConfig.Field1 = "11111";
        tmpConfig.Field2 = "22222";
    }
}

7.验证选项

安装包

	<ItemGroup>
		<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
		<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
		<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
		<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="7.0.0" />
	</ItemGroup>

7.1委托验证

image-20231113223337450

var services = new ServiceCollection();
//不是把选项注入到容器,只是注入了该选项的委托
services.Configure<TmpConfig>(c => { c.Field1 = ""; c.Field2 = "22222"; });
//得到OptionsBuilder,进行验证,本质还是执行Configure(可以执行无数多个Configre)
services.AddOptions<TmpConfig>()
    .Validate(optison =>
    {
        if (optison.Field1 == "")
        {
            return false;
        }
        if (optison.Field2 == "")
        {
            return false;
        }
        return true;
    }, "TmpConfig配置有误,请检查!!!");
var container = services.BuildServiceProvider();
var options = container.GetRequiredService<IOptions<TmpConfig>>();

public class TmpConfig
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

7.2 注解验证

image-20231113224308061

var services = new ServiceCollection();
//不是把选项注入到容器,只是注入了该选项的委托
services.Configure<TmpConfig>(c => { c.Field1 = " "; c.Field2 = " "; });
//得到OptionsBuilder,进行验证,本质还是执行Configure(可以执行无数多个Configre)
services.AddOptions<TmpConfig>()
       .ValidateDataAnnotations();
var container = services.BuildServiceProvider();
var options = container.GetRequiredService<IOptions<TmpConfig>>();
Console.WriteLine(options.Value.Field1);

public class TmpConfig
{
    [RegularExpression(@"/^.+$/", ErrorMessage = "不能为空")]
    public string Field1 { get; set; }
    [RegularExpression(@"/^.+$/", ErrorMessage = "不能为空")]
    public string Field2 { get; set; }
}
posted @   peng_boke  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示