Loading

asp.net core之Options

本文将介绍 ASP.NET Core 中的 Options 概念和使用方法。Options 是一种配置管理机制,可以将应用程序的配置信息从代码中分离出来,提高代码的可维护性和可测试性。我们将详细介绍如何定义 Options 类、注册 Options、使用 Options,并提供相应的示例代码。此外,我们还将对 IOptions、IOptionsSnapshot、IOptionsMonitor、IConfigureNamedOptions、OptionsBuilder、IValidateOptions、PostConfigureOptions 等相关接口和类进行说明,并给出使用场景示例。

Options 概述

在 ASP.NET Core 中,Options 是一种配置管理机制,它允许将应用程序的配置信息从代码中分离出来,以提高代码的可维护性和可测试性。通过使用 Options,我们可以将配置信息封装到一个或多个 Options 类中,并通过依赖注入将其注入到需要使用配置的组件中。

Options 提供了一种统一的方式来访问配置信息,而不需要直接访问配置文件或配置提供程序。它还支持配置的热更新,即在应用程序运行时修改配置后,可以自动应用新的配置值,而无需重新启动应用程序。

定义 Options 类

在 ASP.NET Core 中,我们可以通过定义一个 Options 类来表示一组相关的配置信息。Options 类是一个普通的 C# 类,其中的属性对应配置的键值对。

public class MyOptions
{
    public string Option1 { get; set; }
    public int Option2 { get; set; }
}

在上面的示例中,我们定义了一个名为 MyOptions 的 Options 类,它包含了两个属性 Option1 和 Option2。
在appsettings.json中添加配置:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "MyOptions": {
    "Option1": "Test",
    "Option2": 123
  }
}

注册 Options

要在 ASP.NET Core 中使用 Options,我们需要将 Options 类注册到依赖注入容器中。可以通过在 ConfigureServices 方法中调用 services.Configure(Configuration.GetSection("SectionName")) 来完成注册。

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
}

使用WebApplication则这样操作:

builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));

在上面的示例中,我们将 MyOptions 类注册为一个 Options,并指定了配置文件中的配置节名称为 "MyOptions"。

使用 Options

在需要使用配置的组件中,我们可以通过依赖注入将 Options 注入,并直接访问 Options 类的属性来获取配置值。

public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

    private readonly MyOptions _options;
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, IOptions<MyOptions> options)
    {
        _logger = logger;
        _options = options.Value;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        // 使用配置值
        var option1Value = _options.Option1;
        var option2Value = _options.Option2;
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

在上面的示例中,我们通过构造函数注入了 IOptions,并在 WeatherForecastController中使用了配置值。
image.png
通过Debug我们可以看到正常获取值。

IOptions、IOptionsSnapshot 和 IOptionsMonitor

在 ASP.NET Core 中,有三个主要的 Options 接口:IOptions、IOptionsSnapshot 和 IOptionsMonitor,它们在不同的场景下提供了不同的配置值获取方式。
IOptions:在每次调用时返回相同的配置值,适用于获取配置值后不会发生变化的场景。
IOptionsSnapshot:在每次调用时返回最新的配置值,适用于获取配置值可能会发生变化的场景。
IOptionsMonitor:实时监控配置值的变化,并在配置值发生变化时提供新的配置值,适用于需要实时响应配置变化的场景。
下面我们把Options分三种模式注入。

public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

    private readonly MyOptions _options;
    private readonly MyOptions _options2;
    private MyOptions _options3;
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, IOptions<MyOptions> options, IOptionsSnapshot<MyOptions> options2, IOptionsMonitor<MyOptions> options3)
    {
        _logger = logger;
        _options = options.Value;
        _options2 = options2.Value;
        _options3 = options3.CurrentValue;
        options3.OnChange(o => _options3 = options3.CurrentValue);
    }
    
    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        // 使用配置值
        var option1Value = _options.Option1;
        var option2Value = _options.Option2;
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

首次请求,可以看到三个内容都是一致的
image.png

接下来修改一下配置文件,注意,不需要重启服务。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "MyOptions": {
    "Option1": "Test2222",
    "Option2": 123456
  }
}

再次请求,可以看到IOptionsSnapshot和IOptionsMonitor都发生了变化。


image.png
这里我们可以看到IOptionsMonitor获取内容不是Value,而是CurrentValue,因为他是实时发生更新变化的。如果我们也需要试试获取最新变化的值,则可以使用OnChange监听变化,然后重新给属性赋值。
比如我们跑的后台任务,或者一些单例服务,在第一次构造器注入options之后就不会变化的场景,可以用这种方式的更新Options的值。

IConfigureNamedOptions、OptionsBuilder 和 IValidateOptions

IConfigureNamedOptions:用于配置特定名称的 Options 对象。可以通过实现该接口来为特定的 Options 类提供配置。
比如:

builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));
builder.Services.Configure<MyOptions>("Abcd",builder.Configuration.GetSection("MyOptions"));

OptionsBuilder:用于配置 Options 对象。可以通过调用 Configure 方法来为 Options 类进行配置。

builder.Services.AddOptions<MyOptions>("OptionsBuilderOptions")
    .Configure(o => 
    {
        o.Option1 = "OptionsBuilderOptions"; 
        o.Option2 = 999; 
    })
    ;

启动服务DEBUG检验一下,发现我们成功取到值了。
image.png

这里需要注意的是IOptions<>是没有Get的方法的,要获取对应名称的Options只能通过IOptionsSnapshot<>或IOptionsMonitor<>。

IValidateOptions:用于验证 Options 对象的配置。可以通过实现该接口来对 Options 进行验证。

public class MyOptionsValidator : IValidateOptions<MyOptions>
{
    public ValidateOptionsResult Validate(string name, MyOptions options)
    {
        // 验证 Options 的配置
        if (options.Option1 == null)
        {
            return ValidateOptionsResult.Fail("Option1 must be specified.");
        }
        return ValidateOptionsResult.Success;
    }
}
builder.Services.AddOptions<MyOptions>("ValidateOptions")
    .Configure(o =>
    {
        o.Option1 = null;
        o.Option2 = 999;
    })
    ;
builder.Services.AddSingleton<IValidateOptions
                              <MyOptions>, MyOptionsValidateOptions>();
public WeatherForecastController(ILogger<WeatherForecastController> logger, IOptions<MyOptions> options, IOptionsSnapshot<MyOptions> options2, IOptionsMonitor<MyOptions> options3)
        {
            _logger = logger;
            _options = options.Value;
            _options2 = options2.Value;
            _options3 = options3.CurrentValue;
            options3.OnChange(o => _options3 = options3.CurrentValue);

            var nameOption = options2.Get("Abcd");
            var nameOption2 = options3.Get("OptionsBuilderOptions");
            var nameOption3 = options3.Get("ValidateOptions");
        }

启动服务,发出请求,可以发现报错了。
image.png

结论

通过合理使用 Options,我们可以更好地管理和配置 ASP.NET Core 应用程序。本文详细介绍了 Options 的概念和使用方法,并对相关接口和类进行了说明和示例。通过使用 Options,我们可以将配置信息从代码中分离出来,提高代码的可维护性和可测试性,同时还能实现配置的热更新和实时响应配置变化。

欢迎进群催更。

posted @ 2023-07-31 11:22  饭勺oO  阅读(846)  评论(2编辑  收藏  举报