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

时间:2019-03-09 06:50:26

标签: c# asp.net-core dependency-injection .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"));
}

我还没有注册任何IOptions,而是将其注入到控制器中

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

IOptions正在使用默认实例进行解析,并且只有在尝试使用它时(并且我期望值不为null时),我才知道错误。

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

2 个答案:

答案 0 :(得分:7)

选项框架由默认主机构建器设置,作为其设置的一部分,因此您无需getIdentifier。但是,这也会确保您可以在任何需要的地方使用AddOptions(),因为该框架会为您提供确切的选项对象。

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

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

例如,如果您需要配置IOptions<T>,则应明确查找它:

Config1

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

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

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

例如,您可以将services.AddOptions<UploadConfig>() .Bind(Configuration.GetSection("UploadConfig")) .Validate(c => !string.IsNullOrEmpty(c.Config1)); 插入到启动公司的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();
}

然后将其注入您的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"); } }

Configure

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

答案 1 :(得分:1)

poke 的好答案,我只想用它完成此操作,以便在不提供任何配置的情况下可以快速启动文件:

public class MyOptions
{
    public string MyValue { get; set; }
}

public void ConfigureServices(IServiceCollection services)
{
    var options = Configuration.GetSection("MyOptions").Get<MyOptions>();
    if (string.IsNullOrWhiteSpace(options?.MyValue))
    {
        throw new ApplicationException("MyValue is not configured!");
    }
}
  

IOptions配置值是延迟读取的。虽然   应用程序启动时可能会读取配置文件,   仅当IOptions.Value为   第一次打电话。

     

当反序列化失败时,由于应用程序配置错误,   此类错误仅在调用IOptions.Value之后出现。这个可以   导致错误配置的发现时间长于   需要。通过在以下位置读取并验证配置值:   应用程序启动,可以避免此问题。

本文还可以帮助您理解:

Is IOptions Bad?

ASP.NET Core 2.2 – Options Validation