Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/blazor-issue-processing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ jobs:
repo: context.repo.repo,
body: `### 🦃 ***Happy Thanksgiving!*** 🍽️
*Stand-by!* A green dinosaur 🦖 will be along shortly to assist.`
This issue has been marked for triage on the Blazor Docs GitHub project, and I'll respond after the Thanksgiving holiday during the first week of December.
We only work on documentation on this repo. If you need product support, close this issue and seek assistance through one or more of the following support channels:
* [Stack Overflow (tagged: 'blazor')](https://stackoverflow.com/questions/tagged/blazor)
* [General ASP.NET Core Slack Team](https://aspnetcore.slack.com/join/shared_invite/zt-1mv5487zb-EOZxJ1iqb0A0ajowEbxByQ#/shared-invite/email)
* [Blazor Gitter](https://gitter.im/aspnet/Blazor)
If you think that you found a potential bug in the framework or have product feedback, close this issue and open a new issue for the ASP.NET Core product unit at [dotnet/aspnetcore issues](https://github.com/dotnet/aspnetcore/issues). Bug reports require a clear explanation of the problem, usually including a minimal repro project placed on GitHub for the product unit engineers to download and run. If you determine with the product unit that it isn't a bug but merely requires documentation, please re-open this docs issue and place a cross-link to your engineering issue discussion.
For problems or feedback on Visual Studio, close this issue and use the [**Report a Problem**](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio) or [**Suggest a Feature**](https://docs.microsoft.com/visualstudio/ide/suggest-a-feature) processes from within VS, which open internal issues for the VS product unit. For more information, see [Visual Studio Feedback](https://developercommunity.visualstudio.com/home).
For problems with Visual Studio Code, close this issue and ask for support on community support forums. For bug reports and product feedback, open an issue on the [microsoft/vscode GitHub repo](https://github.com/microsoft/vscode/issues).`
})
await github.rest.issues.addLabels({
issue_number: context.issue.number,
Expand Down
148 changes: 105 additions & 43 deletions aspnetcore/blazor/forms/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn how to use validation in Blazor forms.
monikerRange: '>= aspnetcore-3.1'
ms.author: wpickett
ms.custom: mvc
ms.date: 11/11/2025
ms.date: 11/25/2025
uid: blazor/forms/validation
---
# ASP.NET Core Blazor forms validation
Expand Down Expand Up @@ -1572,48 +1572,6 @@ The <xref:System.ComponentModel.DataAnnotations.CompareAttribute> doesn't work w

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

## Use validation models from a different assembly

For model validation defined in a different assembly, such as a library or the `.Client` project of a Blazor Web App:

* 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).
* 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.
* In the app, call both the method and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>.

The preceding approach results in validation of the types from both assemblies.

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.

`ServiceCollectionExtensions.cs` (in the `.Client` project):

```csharp
namespace BlazorSample.Client.Extensions;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddValidationForTypesInClient(
this IServiceCollection collection)
{
return collection.AddValidation();
}
}
```

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>:

```csharp
using BlazorSample.Client.Extensions;

...

builder.Services.AddValidationForTypesInClient();
builder.Services.AddValidation();
```

:::moniker-end

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

## Nested objects and collection types

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

```csharp
using System.ComponentModel.DataAnnotations;

[ValidatableType]
public class Order
{
Expand Down Expand Up @@ -1691,6 +1651,8 @@ In the following `OrderPage` component, the <xref:Microsoft.AspNetCore.Component

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.

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.

:::moniker-end

:::moniker range="< aspnetcore-10.0"
Expand Down Expand Up @@ -1750,6 +1712,106 @@ public class ShipDescription

:::moniker-end

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

## Use validation models from a different assembly

<!-- UPDATE 11.0 - The first list item changes when the content
is updated for plain class libs upon
experimental status dropping at 11.0 -->

For model validation defined in a different assembly, such as a library or the `.Client` project of a Blazor Web App:

* 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.
* 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.
* In the app, call both the method and <xref:Microsoft.Extensions.DependencyInjection.ValidationServiceCollectionExtensions.AddValidation%2A>.

The preceding approach results in validation of the types from both assemblies.

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.

`ServiceCollectionExtensions.cs` (in the `.Client` project):

```csharp
namespace BlazorSample.Client.Extensions;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddValidationForTypesInClient(
this IServiceCollection collection)
{
return collection.AddValidation();
}
}
```

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>:

```csharp
using BlazorSample.Client.Extensions;

...

builder.Services.AddValidationForTypesInClient();
builder.Services.AddValidation();
```

<!-- UPDATE 11.0 - The following changes when the content
is updated for plain class libs upon
experimental status dropping at 11.0 -->

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.

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.

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:

> :::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.":::
The warning can be suppressed using any of the following approaches:

* A `<NoWarn>` property in the project file:

```xml
<PropertyGroup>
<NoWarn>$(NoWarn);ASP0029</NoWarn>
</PropertyGroup>
```

* A [`pragma` directive](/cpp/preprocessor/pragma-directives-and-the-pragma-keyword) where the attribute is used:

```csharp
#pragma warning disable ASP0029
[Microsoft.Extensions.Validation.ValidatableType]
#pragma warning restore ASP0029
```

* An [EditorConfig file (`.editorconfig`)](/visualstudio/ide/create-portable-custom-editor-options) rule:

```
dotnet_diagnostic.ASP0029.severity = none
```

If suppressing the warning isn't acceptable, manually create the embedded attribute in the library that the Web and Razor SDKs generate automatically.

`ValidatableTypeAttribute.cs`:

```csharp
namespace Microsoft.Extensions.Validation.Embedded
{
[AttributeUsage(AttributeTargets.Class)]
internal sealed class ValidatableTypeAttribute : Attribute
{
}
}
```

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.

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).

:::moniker-end

## Enable the submit button based on form validation

To enable and disable the submit button based on form validation, the following example:
Expand Down
38 changes: 37 additions & 1 deletion aspnetcore/blazor/fundamentals/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,50 @@ On the client for a Blazor Web App, the environment is determined from the serve
<!--Blazor-WebAssembly:{"environmentName":"Development", ...}-->
```

For a standalone Blazor WebAssembly app, set the environment with the `<WasmApplicationEnvironmentName>` property in the app's project file (`.csproj`). The following example sets the `Staging` environment:
For a standalone Blazor WebAssembly app, set the environment with the `<WasmApplicationEnvironmentName>` MSBuild property in the app's project file (`.csproj`). The following example sets the `Staging` environment:

```xml
<WasmApplicationEnvironmentName>Staging</WasmApplicationEnvironmentName>
```

The default environments are `Development` for build and `Production` for publish.

There are several approaches for setting the environment in a standalone Blazor WebAssembly app during build/publish operations and one approach for an app starting or running on the client:

* Set the property value when `dotnet build` or `dotnet publish` is executed. The following example sets the environment to `Staging` when an app is published:

```dotnetcli
dotnet publish -p:WasmApplicationEnvironmentName=Staging
```

* Set the property during build or publish based on the app's configuration in Visual Studio. The following property groups can be used in the app's project file or any publish configuration file (`.pubxml`). Add additional property groups for other build configurations in use.

```xml
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<WasmApplicationEnvironmentName>Development</WasmApplicationEnvironmentName>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<WasmApplicationEnvironmentName>Production</WasmApplicationEnvironmentName>
</PropertyGroup>
```

* The environment can be set based on the use of a publish profile. In the following example, the first condition sets the environment to `Development` when no publish profile is used (applies to both build and publish operations without a profile), while the second condition covers setting the environment to `Production` when any publish profile is used:

```xml
<PropertyGroup Condition="'$(PublishProfile)' == ''">
<WasmApplicationEnvironmentName>Development</WasmApplicationEnvironmentName>
</PropertyGroup>

<PropertyGroup Condition="'$(PublishProfile)' != ''">
<WasmApplicationEnvironmentName>Production</WasmApplicationEnvironmentName>
</PropertyGroup>
```

* Create a custom server-side web API endpoint. The standalone Blazor WebAssembly app requests its environment from the web API either at app startup or on-demand while it's running. The value should be passed to [`WebAssemblyStartOptions`](https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/WebAssemblyStartOptions.ts#L7) or with [`withApplicationEnvironment`](https://github.com/dotnet/aspnetcore/blob/main/src/Components/dotnet-runtime-js/dotnet.d.ts#L110).

[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]

:::moniker-end

:::moniker range=">= aspnetcore-8.0 < aspnetcore-10.0"
Expand Down
2 changes: 2 additions & 0 deletions aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ The default environments are:
* `Development` for build.
* `Production` for publish.

For more information, see <xref:blazor/fundamentals/environments#set-the-environment>.

### Boot configuration file inlined

Blazor's boot configuration, which prior to the release of .NET 10 existed in a file named `blazor.boot.json`, has been inlined into the `dotnet.js` script. This only affects developers who are interacting directly with the `blazor.boot.json` file, such as when developers are:
Expand Down
Loading