diff --git a/aspnetcore/fundamentals/minimal-apis/validation.md b/aspnetcore/fundamentals/minimal-apis/validation.md new file mode 100644 index 000000000000..6632e98dbf68 --- /dev/null +++ b/aspnetcore/fundamentals/minimal-apis/validation.md @@ -0,0 +1,70 @@ +--- +title: Validation in Minimal API apps +author: Youssef1313 +description: Use Microsoft.Extensions.Validation in Minimal API apps to validate API models. +ms.author: ygerges +ms.date: 07/08/2026 +monikerRange: '>= aspnetcore-10.0' +uid: fundamentals/minimal-apis/validation + +# customer intent: As an ASP.NET developer, I want to have automatic validation of models in Minimal API parameters. +--- + +# Validation in Minimal API apps + +In .NET 10, Microsoft.Extensions.Validation was introduced to support complex model validation. + +To enable validation, call `AddValidation` on the `IServiceCollection` instance in the web application entry point. + +```csharp +builder.Services.AddValidation(); +``` + +## Parameter validation + +Parameter validation is the first step in the validation pipeline in minimal API endpoints. It involves the following steps: + +1. Validate `ValidationAttribute`s applied to the minimal API parameter. +1. If the parameter type is `IEnumerable`, validate the type for all non-null elements. Otherwise, validate the type for the value. + +> [!NOTE] +> There is a known limitation currently that nullable value types declared as minimal API parameters don't get validated. +> For more information, see [dotnet/aspnetcore#67033](https://github.com/dotnet/aspnetcore/issues/67033). + +If the minimal API parameter type is `IEnumerable`, a type validation for all non-null elements happens. Otherwise, a single type validation for the value happens. + +## Type validation + +Type validation is the next step after parameter validation. It involves the following steps: + +1. Validate properties on the type. If any errors are found, the validation process stops. +1. Validate type-level `ValidationAttribute`s. If any errors are found, the validation process stops. +1. Validate `IValidatableObject`, if it's implemented. + +## Property validation + +Property validation happens as part of the type validation as explained in the previous section. It involves the following steps: + +1. Validate `ValidationAttribute`s applied on the property. +1. If the property value is `IEnumerable`, perform type validation for all non-null elements. Otherwise, perform a single type validation for the value. + +## Explicit validation skipping + +When needed, you can skip validation for a specific parameter, type, or property by applying the `SkipValidationAttribute`. + +## Force-generate validatable type information + +The Microsoft.Extensions.Validation package works via a Roslyn source generator that detects the object graph and types for minimal API endpoint parameters. + +In some cases, not all types that will be part of the object graph can be determined at compile time. In these cases, you can force the source generator to consider a type for validation by applying `ValidatableTypeAttribute` to that type. + +## Async validation support + +Starting in .NET 11, Microsoft.Extensions.Validation supports async validation. You can apply custom implementations of `AsyncValidationAttribute` to parameters, types, or properties, and they will be called asynchronously. In addition, types can implement `IAsyncValidatableObject` as well. + +> [!IMPORTANT] +> Both `IAsyncValidatableObject` and `AsyncValidationAttribute` require you to implement the validation logic synchronously **and** asynchronously. +> For minimal API validation using `Microsoft.Extensions.Validation`, the framework always calls the async path and never the sync path. +> The sync and async paths are never intended to both be called together. If your implementation can't support the sync path, throw `InvalidOperationException`. + +When validating properties on a type, we start all validation tasks concurrently. Similarly, when we validate `IEnumerable`s, we start validation tasks for elements concurrently. \ No newline at end of file diff --git a/aspnetcore/includes/validation-package-net10.md b/aspnetcore/includes/validation-package-net10.md deleted file mode 100644 index dba852f7dab6..000000000000 --- a/aspnetcore/includes/validation-package-net10.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: .NET 10 validation package information -ai-usage: ai-assisted -ms.author: wpickett -ms.date: 08/28/2025 ---- - - -## Validation in .NET 10 - -In .NET 10, the unified validation APIs have been moved to the `Microsoft.Extensions.Validation` NuGet package. This change makes the validation APIs available outside of ASP.NET Core HTTP scenarios. - -To use the `Microsoft.Extensions.Validation` APIs: - -* Add the following package reference: - - ```xml - - ``` - - The functionality remains the same but now requires an explicit package reference. - -* Register validation services with dependency injection: - - ```csharp - builder.Services.AddValidation(); - ``` \ No newline at end of file diff --git a/aspnetcore/mvc/models/validation.md b/aspnetcore/mvc/models/validation.md index b23f10b7449b..2d224d5a17ce 100644 --- a/aspnetcore/mvc/models/validation.md +++ b/aspnetcore/mvc/models/validation.md @@ -18,10 +18,6 @@ This article explains how to validate user input in an ASP.NET Core MVC or Razor :::moniker-end -:::moniker range=">= aspnetcore-10.0" -[!INCLUDE[](~/includes/validation-package-net10.md)] -:::moniker-end - :::moniker range=">= aspnetcore-7.0" ## Model state diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 0895dd74c2b2..90d1f97d75ca 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -1168,6 +1168,8 @@ items: uid: fundamentals/minimal-apis/responses - name: Filters uid: fundamentals/minimal-apis/min-api-filters + - name: Validation in minimal API apps + uid: fundamentals/minimal-apis/validation - name: Unit and integration tests uid: fundamentals/minimal-apis/test-min-api - name: Middleware diff --git a/aspnetcore/tutorials/first-mvc-app/validation.md b/aspnetcore/tutorials/first-mvc-app/validation.md index b789e8513a3a..6e6f9475f71b 100644 --- a/aspnetcore/tutorials/first-mvc-app/validation.md +++ b/aspnetcore/tutorials/first-mvc-app/validation.md @@ -26,8 +26,6 @@ One of the design tenets of MVC is [DRY](https://wikipedia.org/wiki/Don%27t_repe The validation support provided by MVC and Entity Framework Core is a good example of the DRY principle in action. You can declaratively specify validation rules in one place (in the model class) and the rules are enforced everywhere in the app. -[!INCLUDE[](~/includes/validation-package-net10.md)] - ## Delete the previously edited data In the next step, validation rules are added that don't allow null values.