Skip to content

Commit b492595

Browse files
committed
ioptions-validation-minivalidation
1 parent f17d99b commit b492595

File tree

4 files changed

+144
-0
lines changed

4 files changed

+144
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="MiniValidation" Version="0.7.4" />
11+
</ItemGroup>
12+
13+
</Project>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using Microsoft.Extensions.Options;
3+
using MiniValidation;
4+
5+
var builder = WebApplication.CreateBuilder(args);
6+
7+
builder.Services.AddOptions<MySettings>()
8+
.BindConfiguration("MySettings")
9+
.ValidateMiniValidation() // <- Enable validation
10+
.ValidateOnStart(); // <- Validate on app start
11+
12+
// Explicitly register the settings object by delegating to the IOptions object
13+
builder.Services.AddSingleton(resolver =>
14+
resolver.GetRequiredService<IOptions<MySettings>>().Value);
15+
16+
var app = builder.Build();
17+
18+
// app.MapGet("/", (IOptions<MySettings> options) => options.Value);
19+
app.MapGet("/", (MySettings options) => options);
20+
21+
app.Run();
22+
23+
public class MySettings
24+
{
25+
[Required]
26+
public string DisplayName { get; set; }
27+
28+
[Required]
29+
public NestedSettings Nested { get; set; }
30+
31+
public class NestedSettings
32+
{
33+
[Required]
34+
public string Value { get; set; }
35+
36+
[Range(1, 100)]
37+
public int Count { get; set; }
38+
}
39+
}
40+
41+
public static class MiniValidationExtensions
42+
{
43+
public static OptionsBuilder<TOptions> ValidateMiniValidation<TOptions>(
44+
this OptionsBuilder<TOptions> optionsBuilder) where TOptions : class
45+
{
46+
optionsBuilder.Services.AddSingleton<IValidateOptions<TOptions>>(
47+
new MiniValidationValidateOptions<TOptions>(optionsBuilder.Name));
48+
return optionsBuilder;
49+
}
50+
}
51+
52+
public class MiniValidationValidateOptions<TOptions>
53+
: IValidateOptions<TOptions> where TOptions : class
54+
{
55+
public MiniValidationValidateOptions(string? name)
56+
{
57+
Name = name;
58+
}
59+
60+
public string? Name { get; }
61+
62+
public ValidateOptionsResult Validate(string? name, TOptions options)
63+
{
64+
// Null name is used to configure all named options.
65+
if (Name != null && Name != name)
66+
{
67+
// Ignored if not validating this instance.
68+
return ValidateOptionsResult.Skip;
69+
}
70+
71+
// Ensure options are provided to validate against
72+
ArgumentNullException.ThrowIfNull(options);
73+
74+
if (MiniValidator.TryValidate(options, out var validationErrors))
75+
{
76+
return ValidateOptionsResult.Success;
77+
}
78+
79+
var typeName = options.GetType().Name;
80+
var errors = new List<string>();
81+
foreach (var (member, memberErrors) in validationErrors)
82+
{
83+
errors.Add($"DataAnnotation validation failed for '{typeName}' member: '{member}' with errors: '{string.Join("', '", memberErrors)}'.");
84+
}
85+
86+
return ValidateOptionsResult.Fail(errors);
87+
}
88+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"iisSettings": {
3+
"windowsAuthentication": false,
4+
"anonymousAuthentication": true,
5+
"iisExpress": {
6+
"applicationUrl": "http://localhost:27028",
7+
"sslPort": 44379
8+
}
9+
},
10+
"profiles": {
11+
"StronglyTypedValidation": {
12+
"commandName": "Project",
13+
"dotnetRunMessages": true,
14+
"launchBrowser": true,
15+
"applicationUrl": "https://localhost:7282;http://localhost:5101",
16+
"environmentVariables": {
17+
"ASPNETCORE_ENVIRONMENT": "Development"
18+
}
19+
},
20+
"IIS Express": {
21+
"commandName": "IISExpress",
22+
"launchBrowser": true,
23+
"environmentVariables": {
24+
"ASPNETCORE_ENVIRONMENT": "Development"
25+
}
26+
}
27+
}
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*",
9+
"MySettings": {
10+
"DisplayName": "Display",
11+
"Nested" : {
12+
"Count": 0
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)