Arcturus.Extensions.Validation.AspNetCore
2026.3.15.316
dotnet add package Arcturus.Extensions.Validation.AspNetCore --version 2026.3.15.316
NuGet\Install-Package Arcturus.Extensions.Validation.AspNetCore -Version 2026.3.15.316
<PackageReference Include="Arcturus.Extensions.Validation.AspNetCore" Version="2026.3.15.316" />
<PackageVersion Include="Arcturus.Extensions.Validation.AspNetCore" Version="2026.3.15.316" />
<PackageReference Include="Arcturus.Extensions.Validation.AspNetCore" />
paket add Arcturus.Extensions.Validation.AspNetCore --version 2026.3.15.316
#r "nuget: Arcturus.Extensions.Validation.AspNetCore, 2026.3.15.316"
#:package Arcturus.Extensions.Validation.AspNetCore@2026.3.15.316
#addin nuget:?package=Arcturus.Extensions.Validation.AspNetCore&version=2026.3.15.316
#tool nuget:?package=Arcturus.Extensions.Validation.AspNetCore&version=2026.3.15.316
Arcturus.Extensions.Validation.AspNetCore
Provides compile-time validation for ASP.NET Core Minimal API endpoints using source generators. This package eliminates reflection overhead and provides type-safe validation with zero runtime cost.
Features
- ✅ Zero Reflection - All validation logic generated at compile-time
- ✅ Type-Safe - Uses pattern matching for parameter type checking
- ✅ High Performance - Direct method calls instead of reflection
- ✅ AOT Compatible - Works with Native AOT scenarios
- ✅ DataAnnotations Support - Validates using standard
System.ComponentModel.DataAnnotations - ✅ Automatic Detection - Source generator automatically detects types that need validation
Installation
dotnet add package Arcturus.Extensions.Validation.AspNetCore
Usage
1. Define your request model with validation attributes
public record CreateUserRequest
{
[Required]
[StringLength(100)]
public string Name { get; init; } = string.Empty;
[Required]
[EmailAddress]
public string Email { get; init; } = string.Empty;
[Range(18, 120)]
public int Age { get; init; }
}
2. Add validation to your endpoint
app.MapPost("/users", (CreateUserRequest request) =>
{
// Your logic here - request is already validated
return Results.Ok(new { Id = 1, request.Name, request.Email });
})
.ValidateParameters(); // Add this extension method
Or using the filter directly:
app.MapPost("/users", (CreateUserRequest request) =>
{
return Results.Ok(new { Id = 1, request.Name, request.Email });
})
.AddEndpointFilter<ValidateParametersFilter>();
3. Validation happens automatically
When a request comes in:
- The source generator creates type-specific validation code at compile-time
- Invalid requests return
400 Bad RequestwithValidationProblemdetails - Valid requests proceed to your handler
Example error response:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"Name": ["The Name field is required."],
"Email": ["The Email field is not a valid e-mail address."]
}
}
How It Works
Compile-Time Code Generation
When you build your project:
- The source generator detects endpoints using
.ValidateParameters()or.AddEndpointFilter<ValidateParametersFilter>() - Analyzes the parameter types in those endpoints
- Generates:
ValidationExtensions.TryValidate()methods for each typeValidationHelperimplementation with type-specific pattern matching
Generated Code Example
For the CreateUserRequest above, the generator creates:
// ValidationExtensions.g.cs
internal static partial class ValidationExtensions
{
internal static bool TryValidate(this CreateUserRequest parameters, out Dictionary<string, string[]> errors)
{
errors = new Dictionary<string, string[]>();
var validationContext = new ValidationContext(parameters);
var validationResults = new List<ValidationResult>();
if (!Validator.TryValidateObject(parameters, validationContext, validationResults, validateAllProperties: true))
{
foreach (var validationResult in validationResults)
{
var propertyName = validationResult.MemberNames.FirstOrDefault() ?? "Unknown";
errors[propertyName] = new[] { validationResult.ErrorMessage ?? "Validation failed" };
}
}
return errors.Count == 0;
}
}
// ValidationHelper.g.cs
internal static partial class ValidationHelper
{
static partial void InitializeValidation()
{
_validateFunc = ValidateArgumentsImpl;
}
private static object? ValidateArgumentsImpl(IList<object?> arguments)
{
foreach (var argument in arguments)
{
if (argument is null)
continue;
if (argument is global::MyNamespace.CreateUserRequest param0)
{
if (!param0.TryValidate(out var errors0))
{
return Results.ValidationProblem(errors0);
}
}
}
return null;
}
}
Runtime Execution
At runtime, the ValidateParametersFilter:
- Calls the generated
ValidationHelper.ValidateArguments() - Uses pattern matching (
isoperator) to identify parameter types - Calls the appropriate
TryValidate()extension method - Returns
ValidationProblemif validation fails
No reflection. No performance overhead.
Advanced Scenarios
C# 11+ Required Properties
The generator also validates required properties:
public record UpdateUserRequest
{
public required string Name { get; init; }
public required string Email { get; init; }
}
Multiple Parameters
app.MapPost("/complex", (CreateUserRequest user, SettingsRequest settings) =>
{
// Both parameters are validated
return Results.Ok();
})
.ValidateParameters();
Debugging Generated Code
To view generated code, add to your .csproj:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
Generated files will be in obj/Generated/.
Performance Comparison
| Approach | Method | Time (ns) | Allocations |
|---|---|---|---|
| Source Generator | Direct call | ~500 | Minimal |
| Reflection | MethodInfo.Invoke() |
~5,000 | High |
10x faster with significantly fewer allocations
Requirements
- .NET 9.0 or later
- C# 14.0
- ASP.NET Core
NuGet Package Structure
The package includes:
- Runtime library (
Arcturus.Extensions.Validation.AspNetCore.dll) - Source generator (
analyzers/dotnet/cs/Arcturus.Validation.CodeGenerator.dll) - Build props for proper configuration
The source generator runs automatically during build - no additional configuration needed.
Troubleshooting
Generator not running?
- Clean and rebuild:
dotnet clean && dotnet build - Check that endpoints use
.ValidateParameters()or.AddEndpointFilter<ValidateParametersFilter>() - Ensure your models have validation attributes
- View build output for generator diagnostics
Validation not working?
- Check that your model properties have validation attributes
- Ensure the model is a parameter in the endpoint handler
License
MIT
Contributing
Contributions welcome! Please open an issue or PR on GitHub.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.3.15.316 | 80 | 3/15/2026 |
| 2026.3.12.308 | 88 | 3/12/2026 |
| 2026.3.11.295 | 86 | 3/11/2026 |
| 2026.3.11.291 | 80 | 3/11/2026 |
| 2026.3.9.275 | 77 | 3/9/2026 |
| 2026.3.9.271 | 77 | 3/9/2026 |
| 2026.3.9.269 | 84 | 3/9/2026 |
| 2026.3.7.268 | 76 | 3/7/2026 |
| 2026.2.26.266 | 89 | 2/26/2026 |
| 2026.2.25.258 | 91 | 2/25/2026 |
| 2026.2.25.257 | 88 | 2/25/2026 |
| 2026.2.25.256 | 90 | 2/25/2026 |
| 2026.2.25.255 | 88 | 2/25/2026 |
| 2026.2.25.253 | 76 | 2/25/2026 |
| 2026.2.25.252 | 84 | 2/25/2026 |