MVC 6配置验证

4
在MVC 6项目中,我有以下配置文件...
{
  "ServiceSettings" :
  {
    "Setting1" : "Value"
  }
}

...以及以下的类...

public class ServiceSettings
{
  public Setting1
  {
    get;

    set;
  }
}

Startup类的ConfigureServices方法中,我添加了以下代码行...
services.Configure<ServiceSettings>(Configuration.GetConfigurationSection("ServiceSettings"));

如果需要验证Setting1的值,我该怎么做?我可以在实际使用IOptions<ServiceSettings>实例的时候进行验证,但是如果Setting1的值对服务的操作是必要的,我希望能够尽早捕获这个问题,而不是在下游进一步处理。旧的ConfigurationSection对象允许您指定规则,在读取配置数据时如果出现无效内容就会抛出异常。
4个回答

5
您可以执行类似以下的操作:
services.Configure<ServiceSettings>(serviceSettings =>
{
    // bind the newed-up type with the data from the configuration section
    ConfigurationBinder.Bind(serviceSettings, Configuration.GetConfigurationSection(nameof(ServiceSettings)));

    // modify/validate these settings if you want to
});

// your settings should be available through DI now

我将另一个解决方案标记为答案,尽管您的解决方案也是正确的。如果可以的话,我会将两个都标记为答案。感谢您的贡献。 - Jason Richmeier

2

ASP.Net-Core 2.0 中优雅的选项验证方法

netcore2.0 开始,使用 PostConfigure 是一种很好的方式。该函数也接受一个配置委托,但是它是在最后执行的,所以此时所有设置都已经完成。

// Configure options as usual
services.Configure<MyOptions>(Configuration.GetSection("section"));

// Then, immediately afterwards define a delegate to validate the FINAL options later
services.PostConfigure<MyOptions>(myOptions => {
    // Take the fully configured myOptions and run validation checks...
    if (myOptions.Option1 == null) {
        throw new Exception("Option1 has to be specified");
    }
});

2

我已经在ServiceSettings中的所有必填属性上标记了[Required],并在Startup.ConfigureServices中添加了以下内容:

services.Configure<ServiceSettings>(settings =>
{
    ConfigurationBinder.Bind(Configuration.GetSection("ServiceSettings"), settings);

    EnforceRequiredStrings(settings);
})

以下是与Startup相关的内容:

private static void EnforceRequiredStrings(object options)
{
    var properties = options.GetType().GetTypeInfo().DeclaredProperties.Where(p => p.PropertyType == typeof(string));
    var requiredProperties = properties.Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(RequiredAttribute)));

    foreach (var property in requiredProperties)
    {
        if (string.IsNullOrEmpty((string)property.GetValue(options)))
            throw new ArgumentNullException(property.Name);
    }
}

我已将您的解决方案标记为答案,因为它与我想出的解决方案相似(在阅读您的解决方案之前)。我选择实现IValidatableObject接口而不是属性。在这种情况下,这可能更多是一种偏好而不是必须。 - Jason Richmeier

0
如果不介意向配置对象添加更多代码,就可以像Andrew Lock博客中所描述的那样,在启动时实现验证。他创建了NuGet包,以避免自己添加代码。 如果您想探索更多可能性,还有ConfigurationValidation包提供一些扩展的配置验证功能(个人观点:我是作者)。 如果您正在使用FluentValidation进行某些操作,也有可能将其用于配置验证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接