Skip to content

Commit

Permalink
ioptions-validation-minivalidation
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewlock committed Jun 15, 2023
1 parent f17d99b commit b492595
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MiniValidation" Version="0.7.4" />
</ItemGroup>

</Project>
88 changes: 88 additions & 0 deletions ioptions-validation-minivalidation/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Options;
using MiniValidation;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOptions<MySettings>()
.BindConfiguration("MySettings")
.ValidateMiniValidation() // <- Enable validation
.ValidateOnStart(); // <- Validate on app start

// Explicitly register the settings object by delegating to the IOptions object
builder.Services.AddSingleton(resolver =>
resolver.GetRequiredService<IOptions<MySettings>>().Value);

var app = builder.Build();

// app.MapGet("/", (IOptions<MySettings> options) => options.Value);
app.MapGet("/", (MySettings options) => options);

app.Run();

public class MySettings
{
[Required]
public string DisplayName { get; set; }

[Required]
public NestedSettings Nested { get; set; }

public class NestedSettings
{
[Required]
public string Value { get; set; }

[Range(1, 100)]
public int Count { get; set; }
}
}

public static class MiniValidationExtensions
{
public static OptionsBuilder<TOptions> ValidateMiniValidation<TOptions>(
this OptionsBuilder<TOptions> optionsBuilder) where TOptions : class
{
optionsBuilder.Services.AddSingleton<IValidateOptions<TOptions>>(
new MiniValidationValidateOptions<TOptions>(optionsBuilder.Name));
return optionsBuilder;
}
}

public class MiniValidationValidateOptions<TOptions>
: IValidateOptions<TOptions> where TOptions : class
{
public MiniValidationValidateOptions(string? name)
{
Name = name;
}

public string? Name { get; }

public ValidateOptionsResult Validate(string? name, TOptions options)
{
// Null name is used to configure all named options.
if (Name != null && Name != name)
{
// Ignored if not validating this instance.
return ValidateOptionsResult.Skip;
}

// Ensure options are provided to validate against
ArgumentNullException.ThrowIfNull(options);

if (MiniValidator.TryValidate(options, out var validationErrors))
{
return ValidateOptionsResult.Success;
}

var typeName = options.GetType().Name;
var errors = new List<string>();
foreach (var (member, memberErrors) in validationErrors)
{
errors.Add($"DataAnnotation validation failed for '{typeName}' member: '{member}' with errors: '{string.Join("', '", memberErrors)}'.");
}

return ValidateOptionsResult.Fail(errors);
}
}
28 changes: 28 additions & 0 deletions ioptions-validation-minivalidation/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:27028",
"sslPort": 44379
}
},
"profiles": {
"StronglyTypedValidation": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7282;http://localhost:5101",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
15 changes: 15 additions & 0 deletions ioptions-validation-minivalidation/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MySettings": {
"DisplayName": "Display",
"Nested" : {
"Count": 0
}
}
}

0 comments on commit b492595

Please sign in to comment.