Skip to content

Commit e97cb6a

Browse files
authored
Move section and add guidance on plain class libs (#36398)
1 parent 77b1c98 commit e97cb6a

File tree

1 file changed

+105
-43
lines changed

1 file changed

+105
-43
lines changed

aspnetcore/blazor/forms/validation.md

Lines changed: 105 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Learn how to use validation in Blazor forms.
55
monikerRange: '>= aspnetcore-3.1'
66
ms.author: wpickett
77
ms.custom: mvc
8-
ms.date: 11/11/2025
8+
ms.date: 11/25/2025
99
uid: blazor/forms/validation
1010
---
1111
# ASP.NET Core Blazor forms validation
@@ -1572,48 +1572,6 @@ The <xref:System.ComponentModel.DataAnnotations.CompareAttribute> doesn't work w
15721572

15731573
:::moniker range=">= aspnetcore-10.0"
15741574

1575-
## Use validation models from a different assembly
1576-
1577-
For model validation defined in a different assembly, such as a library or the `.Client` project of a Blazor Web App:
1578-
1579-
* If the library is a plain class library (it isn't based on the `Microsoft.NET.Sdk.Web` or `Microsoft.NET.Sdk.Razor` SDKs), add a package reference to the library for the [`Microsoft.Extensions.Validation` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Validation).
1580-
* Create a method in the library or `.Client` project that receives an <xref:Microsoft.Extensions.DependencyInjection.IServiceCollection> instance as an argument and calls <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A> on it.
1581-
* In the app, call both the method and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>.
1582-
1583-
The preceding approach results in validation of the types from both assemblies.
1584-
1585-
In the following example, the `AddValidationForTypesInClient` method is created for the `.Client` project of a Blazor Web App for validation using types defined in the `.Client` project.
1586-
1587-
`ServiceCollectionExtensions.cs` (in the `.Client` project):
1588-
1589-
```csharp
1590-
namespace BlazorSample.Client.Extensions;
1591-
1592-
public static class ServiceCollectionExtensions
1593-
{
1594-
public static IServiceCollection AddValidationForTypesInClient(
1595-
this IServiceCollection collection)
1596-
{
1597-
return collection.AddValidation();
1598-
}
1599-
}
1600-
```
1601-
1602-
In the server project's `Program` file, add the namespace and call the `.Client` project's service collection extension method (`AddValidationForTypesInClient`) and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>:
1603-
1604-
```csharp
1605-
using BlazorSample.Client.Extensions;
1606-
1607-
...
1608-
1609-
builder.Services.AddValidationForTypesInClient();
1610-
builder.Services.AddValidation();
1611-
```
1612-
1613-
:::moniker-end
1614-
1615-
:::moniker range=">= aspnetcore-10.0"
1616-
16171575
## Nested objects and collection types
16181576

16191577
Blazor form validation includes support for validating properties of nested objects and collection items with the built-in <xref:Microsoft.AspNetCore.Components.Forms.DataAnnotationsValidator>.
@@ -1643,6 +1601,8 @@ In the following `Order` class, the `[ValidatableType]` attribute is required on
16431601
`Order.cs`:
16441602

16451603
```csharp
1604+
using System.ComponentModel.DataAnnotations;
1605+
16461606
[ValidatableType]
16471607
public class Order
16481608
{
@@ -1691,6 +1651,8 @@ In the following `OrderPage` component, the <xref:Microsoft.AspNetCore.Component
16911651

16921652
The requirement to declare the model types outside of Razor components (`.razor` files) is due to the fact that both the new validation feature and the Razor compiler itself are using a source generator. Currently, output of one source generator can't be used as an input for another source generator.
16931653

1654+
For guidance on using validation models from a different assembly, see the [Use validation models from a different assembly](#use-validation-models-from-a-different-assembly) section.
1655+
16941656
:::moniker-end
16951657

16961658
:::moniker range="< aspnetcore-10.0"
@@ -1750,6 +1712,106 @@ public class ShipDescription
17501712

17511713
:::moniker-end
17521714

1715+
:::moniker range=">= aspnetcore-10.0"
1716+
1717+
## Use validation models from a different assembly
1718+
1719+
<!-- UPDATE 11.0 - The first list item changes when the content
1720+
is updated for plain class libs upon
1721+
experimental status dropping at 11.0 -->
1722+
1723+
For model validation defined in a different assembly, such as a library or the `.Client` project of a Blazor Web App:
1724+
1725+
* If the library is a plain class library (it isn't based on the `Microsoft.NET.Sdk.Web` or `Microsoft.NET.Sdk.Razor` SDKs), add a package reference to the library for the [`Microsoft.Extensions.Validation` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Validation). Additional steps are required for plain class libraries, which are described later in this section.
1726+
* Create a method in the library or `.Client` project that receives an <xref:Microsoft.Extensions.DependencyInjection.IServiceCollection> instance as an argument and calls <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A> on it.
1727+
* In the app, call both the method and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>.
1728+
1729+
The preceding approach results in validation of the types from both assemblies.
1730+
1731+
In the following example, the `AddValidationForTypesInClient` method is created for the `.Client` project of a Blazor Web App for validation using types defined in the `.Client` project.
1732+
1733+
`ServiceCollectionExtensions.cs` (in the `.Client` project):
1734+
1735+
```csharp
1736+
namespace BlazorSample.Client.Extensions;
1737+
1738+
public static class ServiceCollectionExtensions
1739+
{
1740+
public static IServiceCollection AddValidationForTypesInClient(
1741+
this IServiceCollection collection)
1742+
{
1743+
return collection.AddValidation();
1744+
}
1745+
}
1746+
```
1747+
1748+
In the server project's `Program` file, add the namespace and call the `.Client` project's service collection extension method (`AddValidationForTypesInClient`) and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>:
1749+
1750+
```csharp
1751+
using BlazorSample.Client.Extensions;
1752+
1753+
...
1754+
1755+
builder.Services.AddValidationForTypesInClient();
1756+
builder.Services.AddValidation();
1757+
```
1758+
1759+
<!-- UPDATE 11.0 - The following changes when the content
1760+
is updated for plain class libs upon
1761+
experimental status dropping at 11.0 -->
1762+
1763+
The new attributes from the `Microsoft.Extensions.Validation` package (<xref:Microsoft.Extensions.Validation.ValidatableTypeAttribute> and <xref:Microsoft.Extensions.Validation.SkipValidationAttribute>) are published as *experimental* in .NET 10. The package is intended to provide a new shared infrastructure for validation features across frameworks, and publishing experimental types provides greater flexibility for the final design of the public API for better support in consuming frameworks.
1764+
1765+
In Blazor apps, types are made available via a generated embedded attribute. If a web app project that uses the `Microsoft.NET.Sdk.Web` SDK (`<Project Sdk="Microsoft.NET.Sdk.Web">`) or an RCL that uses the `Microsoft.NET.Sdk.Razor` SDK (`<Project Sdk="Microsoft.NET.Sdk.Razor">`) contains Razor components (`.razor`), the framework automatically generates an internal attribute inside the project (`Microsoft.Extensions.Validation.Embedded.ValidatableType`, `Microsoft.Extensions.Validation.Embedded.SkipValidation`). These types are interchangeable with the actual attributes and not marked experimental. In the majority of cases, developers use the `[ValidatableType]`/`[SkipValidation]` attributes on their classes without concern over their source.
1766+
1767+
However, the preceding approach isn't viable in plain class libraries that use the `Microsoft.NET.Sdk` SDK (`<Project Sdk="Microsoft.NET.Sdk">`). Using the types in a plain class library results in an code analysis warning:
1768+
1769+
> :::no-loc text="ASP0029: 'Microsoft.Extensions.Validation.ValidatableTypeAttribute' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.":::
1770+
1771+
The warning can be suppressed using any of the following approaches:
1772+
1773+
* A `<NoWarn>` property in the project file:
1774+
1775+
```xml
1776+
<PropertyGroup>
1777+
<NoWarn>$(NoWarn);ASP0029</NoWarn>
1778+
</PropertyGroup>
1779+
```
1780+
1781+
* A [`pragma` directive](/cpp/preprocessor/pragma-directives-and-the-pragma-keyword) where the attribute is used:
1782+
1783+
```csharp
1784+
#pragma warning disable ASP0029
1785+
[Microsoft.Extensions.Validation.ValidatableType]
1786+
#pragma warning restore ASP0029
1787+
```
1788+
1789+
* An [EditorConfig file (`.editorconfig`)](/visualstudio/ide/create-portable-custom-editor-options) rule:
1790+
1791+
```
1792+
dotnet_diagnostic.ASP0029.severity = none
1793+
```
1794+
1795+
If suppressing the warning isn't acceptable, manually create the embedded attribute in the library that the Web and Razor SDKs generate automatically.
1796+
1797+
`ValidatableTypeAttribute.cs`:
1798+
1799+
```csharp
1800+
namespace Microsoft.Extensions.Validation.Embedded
1801+
{
1802+
[AttributeUsage(AttributeTargets.Class)]
1803+
internal sealed class ValidatableTypeAttribute : Attribute
1804+
{
1805+
}
1806+
}
1807+
```
1808+
1809+
Use the exact namespace (`Microsoft.Extensions.Validation.Embedded`) and class name (`ValidatableTypeAttribute`) in order for the validation source generator to detect and use the type. You can declare a global `using` statement for the namespace, either with a `global using Microsoft.Extensions.Validation.Embedded;` statement or with a `<Using Include="Microsoft.Extensions.Validation.Embedded" />` item in the library's project file.
1810+
1811+
Whichever approach is adopted, denote the presence of the workaround for a future update to your code. Framework updates to ease the adoption of validation types in plain class libraries are planned for .NET 11 (November, 2026).
1812+
1813+
:::moniker-end
1814+
17531815
## Enable the submit button based on form validation
17541816

17551817
To enable and disable the submit button based on form validation, the following example:

0 commit comments

Comments
 (0)