I have an appsettings.json with the following contents:
{
"Settings": {
"Greeting": "Hello World"
}
}
that I associate with
public sealed class SettingsOptions
{
public const string SECTION = "Settings";
[Required(ErrorMessage = "{0} is required.")]
public string Greeting { get; init; } = default!;
[Required(ErrorMessage = "{0} is required.")]
[Range(1, 10, ErrorMessage = "{0} must be between {1} and {2} inclusive.")]
public int Age { get; init; }
}
Note: I intentionally removed Age in appsettings.json to simulate an invalid case.
I expect my console app below throws an exception but apparently it does not when the app starts.
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);
services.AddOptions<SettingsOptions>()
.BindConfiguration(SettingsOptions.SECTION)
.ValidateDataAnnotations()
.ValidateOnStart();
var provider = services.BuildServiceProvider();
#if false // only for simulation
var settings = provider.GetRequiredService<IOptions<SettingsOptions>>().Value;
Console.WriteLine($"greeting: {settings.Greeting}, age: {settings.Age}.");
#endif
Console.WriteLine("Done");
Console.ReadKey();
public sealed class SettingsOptions
{
public const string SECTION = "Settings";
[Required(ErrorMessage = "{0} is required.")]
public string Greeting { get; init; } = default!;
[Required(ErrorMessage = "{0} is required.")]
[Range(1, 10, ErrorMessage = "{0} must be between {1} and {2} inclusive.")]
public int Age { get; init; }
}
It does throw an exception if I enable
#if true// only for simulation
var settings = provider.GetRequiredService<IOptions<SettingsOptions>>().Value;
Console.WriteLine($"greeting: {settings.Greeting}, age: {settings.Age}.");
#endif
I have two questions:
- Why doesn't
ValidateOnStart()throw an exception before other parts need to resolveSettingsOptions? - Why doesn't
[Required]have any effect (it does not throw an exception whenAgeinappsettings.jsonis missing but instead it is set to its default value0)?
Edit:
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="8.0.0" />
It won't work inside the console app unless you implement the generic host in the console app.
ValidateOnStartmethod is addingValidationHostedServicewhich isIHostedServicewhich is triggered onhost.Run().