如何在 DI 设置期间自动验证 appSettings.json 文件中的配置值?

Que*_*n3r 6 c# asp.net-core-mvc .net-core asp.net-core

我向 .NET Core 项目中的 appSettings.json 文件添加了配置。为简单起见,我以数据库设置为例。所以在设置文件中你会有

{
  "Database": {
    "Host": "localhost",
    "Port": 1234,
    "Database": "myDb",
    "Username": "username",
    "Password": "pw",
    "EnablePooling": true
  }
}
Run Code Online (Sandbox Code Playgroud)

在 Startup.cs 文件中配置服务时,我想让这些设置通过依赖注入访问。这个数据模型是

public class DatabaseSettings
{
    public string Host { get; set; }
    public ushort Port { get; set; }
    public string Database { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public bool EnablePooling { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我这样配置

private void SetupSettings(IServiceCollection services)
{
    ServiceProvider serviceProvider = services.BuildServiceProvider();
    IConfiguration configuration = serviceProvider.GetService<IConfiguration>();

    IConfigurationSection databaseConfigurationSection = configuration.GetSection("Database");
    services.Configure<DatabaseSettings>(databaseConfigurationSection);
}
Run Code Online (Sandbox Code Playgroud)

最后,我想验证这些设置。我知道我可以创建一个实现IValidateOptions接口的验证器类。

public class DatabaseSettingsValidator : IValidateOptions<DatabaseSettings>
{
    private readonly IList<string> failures;

    public DatabaseSettingsValidator()
    {
        failures = new List<string>();
    }
    
    public ValidateOptionsResult Validate(string databaseSettingsName, DatabaseSettings databaseSettings)
    {
        if (databaseSettings == null)
            failures.Add($"{databaseSettingsName} are required.");
        
        if (string.IsNullOrEmpty(databaseSettings?.Host))
            failures.Add($"{nameof(databaseSettings.Host)} must not be empty.");
        
        if (string.IsNullOrEmpty(databaseSettings?.Database))
            failures.Add($"{nameof(databaseSettings.Database)} must not be empty.");
        
        if (failures.Any())
            return ValidateOptionsResult.Fail(failures);

        return ValidateOptionsResult.Success;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我必须创建这个类并Validate自己调用该方法吗?也许有这样的示例代码?

.

services.ValidateConfiguration<IOptions<DatabaseSettings>, DatabaseSettingsValidator>();
Run Code Online (Sandbox Code Playgroud)

So you pass in the configured settings and the validator to use.

Zhi*_* Lv 1

但我正在努力解决两个问题:

有没有一种方法可以收集所有失败而不是在一次失败后返回?因此,您将获得一份故障列表,而不必一一修复。

我是否必须自己创建此类并调用 Validate 方法?也许有类似这个示例代码的东西?

services.ValidateConfiguration<IOptions, DatabaseSettingsValidator>(); 因此,您传入配置的设置和要使用的验证器。

是的,我们可以收集所有失败列表并立即显示它们,我们还可以创建一个包含 Validate 方法的类。请检查以下步骤:

首先,由于类名是“ DatabaseSettings ”,因此最好将配置节名称设置为与类名相同:

{
  "DatabaseSettings": {
    "Host": "localhost",
    "Port": 1234,
    "Database": "myDb",
    "Username": "username",
    "Password": "pw",
    "EnablePooling": true
  }
}
Run Code Online (Sandbox Code Playgroud)

[注意] 如果使用不同的名称,该值可能不会映射到数据库设置类,因此在验证数据时,它们都为空。

其次,使用数据注释方法将验证规则添加到模型属性中。

public class DatabaseSettings
{
    [Required]
    public string Host { get; set; }
    [Required]
    public ushort Port { get; set; }
    [Required]
    public string Database { get; set; }
    [Required]
    public string Username { get; set; }
    [Required]
    public string Password { get; set; }
    [Required]
    public bool EnablePooling { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

第三,创建一个包含ConfigureAndValidate方法的ServiceCollectionExtensions类:

public static class ServiceCollectionExtensions
{
    public static IServiceCollection ConfigureAndValidate<T>(this IServiceCollection @this,
        IConfiguration config) where T : class
        => @this
            .Configure<T>(config.GetSection(typeof(T).Name))
            .PostConfigure<T>(settings =>
            {
                var configErrors = settings.ValidationErrors().ToArray();
                if (configErrors.Any())
                {
                    var aggrErrors = string.Join(",", configErrors);
                    var count = configErrors.Length;
                    var configType = typeof(T).Name;
                    throw new ApplicationException(
                        $"Found {count} configuration error(s) in {configType}: {aggrErrors}");
                }
            });
}
Run Code Online (Sandbox Code Playgroud)

然后,注册ConfigureAndValidate服务:

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureAndValidate<DatabaseSettings>(Configuration);
}
Run Code Online (Sandbox Code Playgroud)

最后,获取例外列表。

public class HomeController : Controller
{
    private readonly DatabaseSettings_settings;

    public HomeController(IOptions<DatabaseSettings> settings)
    {
        _settings = settings.Value; // <-- FAIL HERE THROW EXCEPTION
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,测试结果如下(我从 appSettings.json 中删除了主机和用户名):

在此输入图像描述

更详细的信息,你可以查看这个博客:Validating configuration in ASP.NET Core