Asp.Net Core 中的 Options

Asp.Net Core 中的 Options

原文地址: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-5.0

配置类工程软件设计原则:封装(配置类只依赖与之相关的配置)与隔离(配置类互不依赖)

Options 接口

  • IOptions<TOptions>:
  • IOptionsSnapshot<TOptions>: scoped 设计用于被transient 和 scoped 的类依赖
  • IOptionsMonitor<TOptions>: singleton 设计用于对被单例的类依赖
  • IOptionsFactory<TOptions>:
  • IConfigureOptions<TOptions>
  • IPostConfigureOptions<TOptions>
  • IConfigureNamedOptions<TOptions>
  • IOptionsMonitorCache
  • IOptionsMonitor<TOptions>
"Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }
public class PositionOptions //非抽象类,且必须有无参构造函数
{
    public const string Position = "Position"; //field 不绑定

    public string Title { get; set; } // property + read-write + public 绑定
    public string Name { get; set; }
}

绑定方式 1 : 读取最新的配置信息

var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions); //Configuration is ICongiruation

绑定方式 2: 读取最新的配置信息

var positionOptions = Configuration.GetSection(PositionOptions.Position).Get<PositionOptions>();

绑定方式 3:读取一开始的配置信息

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(Configuration.GetSection(PositionOptions.Position));
    
}
public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }   
}

绑定方式 4:读取最新的配置信息,scoped 生命周期

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}
public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }   
}

绑定方式 5:读取最新的配置信息

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}
public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} 
" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

绑定方式 6:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}
public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; }
    public string Model { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<TopItemSettings>(TopItemSettings.Month,
                                       Configuration.GetSection("TopItem:Month"));
    services.Configure<TopItemSettings>(TopItemSettings.Year,
                                        Configuration.GetSection("TopItem:Year"));
}
public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }
}

所有选项都是命名实例。 IConfigureOptions<TOptions> 实例将被视为面向 Options.DefaultName 实例,即 string.Empty。

Options

依赖注入

方法 1(绑定方式 7)

services.AddOptions<MyOptions>("optionalName")
    .Configure<Service1, Service2, Service3, Service4, Service5>(
        (o, s, s2, s3, s4, s5) => 
            o.Property = DoSomethingWith(s, s2, s3, s4, s5));

方法 2 (绑定方式 8)

public class OptionsA: IConfigureOptions<TOptions>{}
service.Add<IConfigureOptions<TOptions>, OptionsA>();
public class OptionsB: IConfigureNamedOptions<TOptions>{}
service.Add<IConfigureNamedOptions<TOptions>, OptionsB>();

validation 验证

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}
public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}
services.AddOptions<MyConfigOptions>()
            .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations().Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2."); 
class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public ValidateOptionsResult Validate(string name, MyConfigOptions options){}
}
services.Configure<MyConfigOptions>(Configuration.GetSection(
                                        MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>());

PostConfiguration

services.PostConfigure<MyOptions>(myOptions => //default name instances
{
    myOptions.Option1 = "post_configured_option1_value";
});
services.PostConfigure<MyOptions>("named_options_1", myOptions => //named instances
{
    myOptions.Option1 = "post_configured_option1_value";
});
services.PostConfigureAll<MyOptions>(myOptions => //all instances
{
    myOptions.Option1 = "post_configured_option1_value";
});

启动时获取配置值

IOptions<TOptions> and IOptionsMonitor<TOptions> 都可用于Configure 方法, 但是不可用于 ConfigureServices

public void Configure(IApplicationBuilder app, 
    IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}
原文地址:https://www.cnblogs.com/ArvinZhao/p/14592364.html