Skip to content

Clarify assembly-sensitive behavior of AddValidation() in .NET 10 Minimal APIs #36899

@gumbarros

Description

@gumbarros

Summary

The current .NET 10 Minimal API validation documentation does not make it clear that AddValidation() may need to be invoked from the same assembly that defines the Minimal API endpoints.

This leads to a scenario where validation appears correctly configured but does not execute at runtime when endpoints are defined in a different assembly than where AddValidation() is registered.

Problem details

This is confusing because:

  • services.AddValidation() is already registered in the host application
  • Request DTOs use validation attributes such as [Required]
  • Invalid payloads are accepted and return 200 OK
  • There is no indication that validation metadata/resolvers are generated or registered in an assembly-sensitive way

After moving validation registration into an extension method defined in the same assembly as the Minimal API endpoints, validation starts working as expected.

Documentation gap

The documentation does not clarify:

  • Whether AddValidation() can be called from any referenced assembly
  • Whether it must be called from the assembly that contains Minimal API endpoint mappings
  • Whether it participates in source generation, interceptor generation, or resolver registration in an assembly-sensitive way

Suggested documentation improvement

Add a section under:

APIs → Minimal APIs → Parameter binding

Proposed subsection: Validation registration and assembly considerations

This section should:

  • Explicitly state any assembly requirements for AddValidation()
  • Explain how validation metadata is discovered
  • Provide a multi-assembly example demonstrating correct and incorrect setups
  • Include troubleshooting guidance for cases where validation silently does not execute

Repro

Project layout

  • AppHost (net10.0) - host application
  • ApiAssembly (net10.0) - contains Minimal API endpoint mappings
  • Contracts (netstandard2.0) - contains request DTOs

Contracts/CreateItemRequest.cs

using System.ComponentModel.DataAnnotations;

namespace Contracts;

public record CreateItemRequest
{
    [Required]
    public string Name { get; init; } = null!;
}

ApiAssembly/EndpointMappings.cs

using Contracts;

namespace ApiAssembly;

public static class EndpointMappings
{
    public static void MapApi(this IEndpointRouteBuilder app)
    {
        app.MapPost("/items", (CreateItemRequest request) =>
        {
            return Results.Ok();
        });
    }
}

Failing setup: AppHost/Program.cs

using ApiAssembly;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddValidation();

var app = builder.Build();

app.MapApi();

app.Run();

Request

POST /items
Content-Type: application/json

{
  "name": ""
}

Expected result

HTTP 400 Bad Request with validation errors for Name.

Actual result

HTTP 200 OK.

Working setup

ApiAssembly/ServiceCollectionExtensions.cs

namespace ApiAssembly;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddApiValidation(this IServiceCollection services)
    {
        services.AddValidation();
        return services;
    }
}

AppHost/Program.cs

using ApiAssembly;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddApiValidation();

var app = builder.Build();

app.MapApi();

app.Run();

With this setup, the same invalid request correctly returns validation errors.

Why this is hard to diagnose

  • The application compiles successfully
  • AddValidation() is already present
  • DTO attributes like [Required] appear correct
  • Runtime behavior differs depending on where validation is registered

Request

Please either:

  1. Document this requirement clearly in the Minimal API validation docs, or
  2. Confirm this is unintended behavior and track it as a product bug

Software versions

  • .NET Core
  • .NET 5.0 or later
  • .NET Framework
  • .NET Standard
dotnet --info output
Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET program, but dotnet-output does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.

Host:
  Version:      10.0.4
  Architecture: x64
  Commit:       80d3e14f5e
  RID:          ubuntu.25.10-x64

.NET SDKs installed:
  10.0.104 [/usr/lib/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 10.0.4 [/usr/lib/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 10.0.4 [/usr/lib/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_BUNDLE_EXTRACT_BASE_DIR           [/home/gumbarros/.cache/dotnet_bundle_extract]

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Metadata

Metadata

Assignees

Labels

Pri1ai-triage-action-planAssigned when an AI generated triage and action plan report is created for an issue.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions