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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Arcturus.Extensions.Validation.AspNetCore" Version="2026.3.15.316" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Arcturus.Extensions.Validation.AspNetCore" Version="2026.3.15.316" />
                    
Directory.Packages.props
<PackageReference Include="Arcturus.Extensions.Validation.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Arcturus.Extensions.Validation.AspNetCore --version 2026.3.15.316
                    
#r "nuget: Arcturus.Extensions.Validation.AspNetCore, 2026.3.15.316"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Arcturus.Extensions.Validation.AspNetCore@2026.3.15.316
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Arcturus.Extensions.Validation.AspNetCore&version=2026.3.15.316
                    
Install as a Cake Addin
#tool nuget:?package=Arcturus.Extensions.Validation.AspNetCore&version=2026.3.15.316
                    
Install as a Cake Tool

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 Request with ValidationProblem details
  • 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:

  1. The source generator detects endpoints using .ValidateParameters() or .AddEndpointFilter<ValidateParametersFilter>()
  2. Analyzes the parameter types in those endpoints
  3. Generates:
    • ValidationExtensions.TryValidate() methods for each type
    • ValidationHelper implementation 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:

  1. Calls the generated ValidationHelper.ValidateArguments()
  2. Uses pattern matching (is operator) to identify parameter types
  3. Calls the appropriate TryValidate() extension method
  4. Returns ValidationProblem if 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?

  1. Clean and rebuild: dotnet clean && dotnet build
  2. Check that endpoints use .ValidateParameters() or .AddEndpointFilter<ValidateParametersFilter>()
  3. Ensure your models have validation attributes
  4. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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