为什么即使未注册也要解决IOptions

har*_*shr 3 c# dependency-injection .net-core asp.net-core asp.net-core-configuration

在我的.NET Core项目中,Configure方法中具有以下设置:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    //services.AddOptions<UploadConfig>(Configuration.GetSection("UploadConfig"));
}
Run Code Online (Sandbox Code Playgroud)

我还没有注册任何东西IOptions,我正在将其注入控制器中

[Route("api/[controller]")]
[ApiController]
public class HelloWorldController : ControllerBase
{
    public HelloWorldController(IOptions<UploadConfig> config)
    {
        var config1 = config.Value.Config1;
    }
 }
Run Code Online (Sandbox Code Playgroud)

IOptions是越来越有默认实例解析,和我只知道,当我尝试使用它(当我所期望的价值是不为空)错误。

我能否以某种方式使其失败,说明实例类型未注册或类似原因?我只想尽早发现错误。

pok*_*oke 7

选项框架由默认主机构建器设置,作为其设置的一部分,因此您不需要AddOptions()自己。但是,这也确保了您可以IOptions<T>在任何地方使用,因为框架将为您提供确切的选项对象。

选项的工作方式是,框架将始终为您提供一个T(只要它可以构造一个)。当您使用例如AddOptions<T>或来设置配置时Configure<T>,实际上会发生的是针对该类型注册配置操作T。并且,当IOptions<T>稍后解析时,所有这些已注册的操作将按照其注册顺序运行。

这意味着配置选项类型是有效的。在这种情况下,将使用该对象的默认值。当然,这也意味着您将无法检测到您是否实际上已经配置了选项类型以及配置是否实际上有效。使用这些值时通常必须这样做。

例如,如果需要Config1配置,则应明确查找它:

public HelloWorldController(IOptions<UploadConfig> config)
{
    if (string.IsNullOrEmpty(config.Value.Config1))
        throw ArgumentException("Config1 is not configured properly");
}
Run Code Online (Sandbox Code Playgroud)

一种替代方法是使用来注册类型的验证操作OptionsBuilder.Validate。重新定义选项对象以验证包含值时,将自动调用此方法。这样,您可以在中央位置设置验证:

services.AddOptions<UploadConfig>()
    .Bind(Configuration.GetSection("UploadConfig"))
    .Validate(c => !string.IsNullOrEmpty(c.Config1));
Run Code Online (Sandbox Code Playgroud)

不幸的是,这也意味着您只能在实际使用这些值时检测到这些问题,如果您没有对应用程序进行全面测试,则可能会忽略这些问题。一种解决方法是在应用程序启动时解析一次选项,并在那里进行验证。

例如,您可以将其注入IOptions<T>启动Configure方法中:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IOptions<UploadConfig> uploadOptions)
{
    // since the options are injected here, they will be constructed and automatically
    // validated if you have configured a validate action

    // …
    app.UseMvc();
}
Run Code Online (Sandbox Code Playgroud)

另外,如果您有多个要验证的选项,并且要运行不适合验证动作的逻辑,则还可以创建一个验证它们的服务:

public class OptionsValidator
{
    private readonly IOptions<UploadConfig> uploadOptions;
    public OptionsValidator(IOptions<UploadConfig> uploadOptions)
    {
        _uploadOptions = uploadOptions;
    }

    public void Validate()
    {
        if (string.IsNullOrEmpty(_uploadOptions.Value.Config1))
            throw Exception("Upload options are not configured properly");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其注入您的Configure

public void Configure(IApplicationBuilder app, IHostingEnvironment env, OptionsValidator optionsValidator)
{
    // validate options explicitly
    optionsValidator.Validate();

    // …
    app.UseMvc();
}
Run Code Online (Sandbox Code Playgroud)

无论您做什么,都请记住,默认情况下,配置源已配置为支持在运行时更新配置。因此,您总是会遇到在运行时配置可能暂时无效的情况。