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:
ValidateOnStart()
throw an exception before other parts need to resolve SettingsOptions
?[Required]
have any effect (it does not throw an exception when Age
in appsettings.json
is missing but instead it is set to its default value 0
)?<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. ValidateOnStart
method is adding ValidationHostedService
which is IHostedService
which is triggered on host.Run()
.