How to validate configuration settings using IValidateOptions in ASP.NET Core 2.2?

前端 未结 4 2189
[愿得一人]
[愿得一人] 2021-02-14 15:57

Microsoft\'s ASP.NET Core documentation briefly mentions that you can implement IValidateOptions to validate configuration settings from appsettings

4条回答
  •  盖世英雄少女心
    2021-02-14 16:43

    I eventually found an example of how this is done in the commit where the options validation feature was added. As with so many things in asp.net core, the answer is to add your validator to the DI container and it will automatically be used.

    With this approach the PolygonConfiguration goes into the DI container after validation and can be injected into the controllers that need it. I prefer this to injecting IOptions into my controllers.

    It appears that the validation code runs the first time an instance of PolygonConfiguration is requested from the container (i.e. when the controller is instantiated). It might be nice to validate earlier during startup, but I'm satisfied with this for now.

    Here's what I ended up doing:

    public class Startup
    {
        public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
        {
            Configuration = configuration;
            Logger = loggerFactory.CreateLogger();
        }
    
        public IConfiguration Configuration { get; }
        private ILogger Logger { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
            //Bind configuration settings
            services.Configure(Configuration.GetSection(nameof(PolygonConfiguration)));
    
            //Add validator
            services.AddSingleton, PolygonConfigurationValidator>();
    
            //Validate configuration and add to DI container
            services.AddSingleton(container =>
            {
                try
                {
                    return container.GetService>().Value;
                }
                catch (OptionsValidationException ex)
                {
                    foreach (var validationFailure in ex.Failures)
                        Logger.LogError($"appSettings section '{nameof(PolygonConfiguration)}' failed validation. Reason: {validationFailure}");
    
                    throw;
                }
            });
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
           ...
        }
    }
    
    

    appSettings.json with some valid and invalid values

    {
      "PolygonConfiguration": {
        "SupportedPolygons": [
          {
            "Description": "Triangle",
            "NumberOfSides": 3
          },
          {
            "Description": "Invalid",
            "NumberOfSides": -1
          },
          {
            "Description": "",
            "NumberOfSides": 6
          }
        ]
      }
    }
    

    The validator class itself

        public class PolygonConfigurationValidator : IValidateOptions
        {
            public ValidateOptionsResult Validate(string name, PolygonConfiguration options)
            {
                if (options is null)
                    return ValidateOptionsResult.Fail("Configuration object is null.");
    
                if (options.SupportedPolygons is null || options.SupportedPolygons.Count == 0)
                    return ValidateOptionsResult.Fail($"{nameof(PolygonConfiguration.SupportedPolygons)} collection must contain at least one element.");
    
                foreach (var polygon in options.SupportedPolygons)
                {
                    if (string.IsNullOrWhiteSpace(polygon.Description))
                        return ValidateOptionsResult.Fail($"Property '{nameof(Polygon.Description)}' cannot be blank.");
    
                    if (polygon.NumberOfSides < 3)
                        return ValidateOptionsResult.Fail($"Property '{nameof(Polygon.NumberOfSides)}' must be at least 3.");
                }
    
                return ValidateOptionsResult.Success;
            }
        }
    

    And the configuration models

        public class Polygon
        {
            public string Description { get; set; }
            public int NumberOfSides { get; set; }
        }
    
        public class PolygonConfiguration
        {
            public List SupportedPolygons { get; set; }
        }
    

提交回复
热议问题