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
2 changes: 1 addition & 1 deletion .github/workflows/blazor-hybrid-issue-processing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### 🏖️🌞 **_Summertime!! Woot!!_** 🏐⛵
body: `### 🧟💀 ***Happy Halloween!!*** 🎃🧛

A green dinosaur 🦖 will be along shortly to assist. *Stand-by ........*`
})
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/blazor-issue-processing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### 🧟💀 *Happy Halloween!!_** 🎃🧛
body: `### 🧟💀 ***Happy Halloween!!*** 🎃🧛

*Stand-by!* ... A green dinosaur 🦖 will be along shortly to assist.`
})
Expand Down
44 changes: 44 additions & 0 deletions aspnetcore/blazor/forms/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,50 @@ The <xref:System.ComponentModel.DataAnnotations.CompareAttribute> doesn't work w

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

## Use validation models from a different assembly

<!-- UPDATE 10.0 - API cross-links -->

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 `AddValidation` on it.
* In the app, call both the method and `AddValidation`.

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

```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
8 changes: 6 additions & 2 deletions aspnetcore/blazor/fundamentals/handle-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ The following `ProcessError` component example merely logs errors, but methods o
```razor
@inject ILogger<ProcessError> Logger

<CascadingValue Value="this">
<CascadingValue Value="this" IsFixed="true">
@ChildContent
</CascadingValue>

Expand All @@ -555,6 +555,8 @@ The following `ProcessError` component example merely logs errors, but methods o

> [!NOTE]
> For more information on <xref:Microsoft.AspNetCore.Components.RenderFragment>, see <xref:blazor/components/index#child-content-render-fragments>.
>
> <xref:Microsoft.AspNetCore.Components.CascadingValue%601.IsFixed%2A?displayProperty=nameWithType> is used to indicate that a cascading parameter doesn't change after initialization.

:::moniker-end

Expand Down Expand Up @@ -648,7 +650,7 @@ The following `ProcessError` component passes itself as a [`CascadingValue`](xre
@using Microsoft.Extensions.Logging
@inject ILogger<ProcessError> Logger

<CascadingValue Value="this">
<CascadingValue Value="this" IsFixed="true">
@ChildContent
</CascadingValue>

Expand All @@ -666,6 +668,8 @@ The following `ProcessError` component passes itself as a [`CascadingValue`](xre

> [!NOTE]
> For more information on <xref:Microsoft.AspNetCore.Components.RenderFragment>, see <xref:blazor/components/index#child-content-render-fragments>.
>
> <xref:Microsoft.AspNetCore.Components.CascadingValue%601.IsFixed%2A?displayProperty=nameWithType> is used to indicate that a cascading parameter doesn't change after initialization.

In the `App` component, wrap the <xref:Microsoft.AspNetCore.Components.Routing.Router> component with the `ProcessError` component. This permits the `ProcessError` component to cascade down to any component of the app where the `ProcessError` component is received as a [`CascadingParameter`](xref:blazor/components/cascading-values-and-parameters#cascadingparameter-attribute).

Expand Down
27 changes: 25 additions & 2 deletions aspnetcore/blazor/globalization-localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn how to render globalized and localized content to users in di
monikerRange: '>= aspnetcore-3.1'
ms.author: wpickett
ms.custom: mvc
ms.date: 10/02/2025
ms.date: 10/23/2025
uid: blazor/globalization-localization
---
# ASP.NET Core Blazor globalization and localization
Expand Down Expand Up @@ -289,7 +289,10 @@ In ***server-side development***, specify the app's supported cultures before an

:::moniker range="< aspnetcore-8.0"

In ***server-side development***, specify the app's supported cultures immediately after Routing Middleware (<xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A>) is added to the processing pipeline. The following example configures supported cultures for United States English and Costa Rican Spanish:
In ***server-side development***, specify the app's supported cultures immediately after Routing Middleware (<xref:Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseRouting%2A>) is added to the processing pipeline. The following example configures supported cultures for United States English and Costa Rican Spanish using the following API:

* <xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.AddSupportedCultures%2A> adds the set of the supported cultures for *globalization* (date, number, and currency formatting).
* <xref:Microsoft.AspNetCore.Builder.RequestLocalizationOptions.AddSupportedUICultures%2A> adds the set of the supported UI cultures *for localization* (translated UI strings for rendering content).

:::moniker-end

Expand All @@ -299,6 +302,26 @@ app.UseRequestLocalization(new RequestLocalizationOptions()
.AddSupportedUICultures(new[] { "en-US", "es-CR" }));
```

In the preceding example, the same supported formatting cultures and UI cultures are specified in a narrow case where the app is only used in the United States and Costa Rica. Alternatively, an app can use a broader set of cultures for date, number, and currency formatting but only provide localized content for the United States and Costa Rica, as the following example demonstrates:

```csharp
var uiCultures = new[] { "en-US", "es-CR" };

var formattingCultures = CultureInfo
.GetCultures(CultureTypes.SpecificCultures)
.Select(c => c.Name)
.ToArray();

var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(uiCultures[0])
.AddSupportedCultures(formattingCultures)
.AddSupportedUICultures(uiCultures);

app.UseRequestLocalization(localizationOptions);
```

In the preceding example, [`CultureTypes.SpecificCultures`](xref:System.Globalization.CultureTypes) returns only cultures that are specific to a country or region—such as `en-US` or `fr-FR`—which come with full, concrete globalization data (for dates, numbers, calendars, and other cultural UI) that .NET can use for accurate formatting and parsing. Neutral cultures, such as `en` or `fr`, may not have complete globalization data, so they aren't included in this list.

For information on ordering the Localization Middleware in the middleware pipeline of the `Program` file, see <xref:fundamentals/middleware/index#middleware-order>.

Use the `CultureExample1` component shown in the [Demonstration component](#demonstration-component) section to study how globalization works. Issue a request with United States English (`en-US`). Switch to Costa Rican Spanish (`es-CR`) in the browser's language settings. Request the webpage again.
Expand Down
13 changes: 13 additions & 0 deletions aspnetcore/blazor/hybrid/tutorials/wpf.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ At the top of the project file, change the SDK to `Microsoft.NET.Sdk.Razor`:
<Project Sdk="Microsoft.NET.Sdk.Razor">
```

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

In the project file's existing `<TargetFramework>` property, add a Windows 10 or later version number:

```xml
<TargetFramework>net10.0-windows10.0.17763.0</TargetFramework>
```

> [!NOTE]
> The preceding guidance on setting the project's target framework version to target Windows 10 or later is a result of switching to the `WebView2CompositionControl` with the release of .NET 10.

:::moniker-end

<!--
The following is a workaround for https://github.com/dotnet/wpf/issues/5697 (fixes https://github.com/dotnet/maui/issues/3526).
Additional open issue on it: https://github.com/dotnet/maui/issues/5861
Expand Down
26 changes: 12 additions & 14 deletions aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn about Event Pipe diagnostics and how to get a Garbage Collect
monikerRange: '>= aspnetcore-10.0'
ms.author: wpickett
ms.custom: mvc
ms.date: 06/04/2025
ms.date: 10/21/2025
uid: blazor/performance/webassembly-event-pipe
---
# ASP.NET Core Blazor WebAssembly Event Pipe diagnostics
Expand All @@ -31,14 +31,13 @@ dotnet workload install wasm-tools
In the app's project file (`.csproj`), add following properties for the duration of the investigation:

```xml
<!-- do not enable diagnostics in production, as it has a negative performance impact -->
<PropertyGroup>
<EnableDiagnostics>true</EnableDiagnostics>
</PropertyGroup>
```

> [!WARNING]
> Don't enable diagnostics in production because it has a negative performance impact.
> Don't enable diagnostics in production because it has a negative performance impact.

Build your app with the `wasm-tools` workload.

Expand All @@ -50,9 +49,9 @@ Take a managed memory dump by calling `collectGcDump` JavaScript API:
globalThis.getDotnetRuntime(0).collectGcDump();
```

Call the preceding API from either a browser devoloper tools console or JavaScript code of the app.
Call the preceding API from either a browser developer tools console or JavaScript code of the app.

A `.nettrace` file is downloaded from the browser into a local folder.
A `.nettrace` file is downloaded from the browser into a local folder, usually the `Downloads` folder on Windows.

Convert the dump to `.gcdump` format using the `dotnet-gcdump` tool. To view the converted `.gcdump` file, use Visual Studio or PrefView.

Expand All @@ -63,12 +62,11 @@ For more information, see [View the GC dump captured from dotnet-gcdump](/dotnet
In the app's project file (`.csproj`), add following properties for the duration of the investigation:

```xml
<!-- do not enable diagnostics in production, as it has a negative performance impact -->
<PropertyGroup>
<EnableDiagnostics>true</EnableDiagnostics>
<!-- disable debugger -->
<!-- Disable debugger -->
<WasmDebugLevel>0</WasmDebugLevel>
<!-- sampling in all methods, see below for filtering options -->
<!-- Sampling in all methods, see below for filtering options -->
<WasmPerformanceInstrumentation>all</WasmPerformanceInstrumentation>
</PropertyGroup>
```
Expand All @@ -86,11 +84,11 @@ Start colllecting CPU samples for 60 seconds by calling the `collectCpuSamples`
globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60});
```

Call the preceding API from either a browser devoloper tools console or JavaScript code of the app.
Call the preceding API from either a browser developer tools console or JavaScript code of the app.

Start using the app to run problematic code.

After the predefined period, the browser downloads a `.nettrace` file into a local folder. To view the `.nettrace` file, use Visual Studio or PrefView.
After the predefined period, the browser downloads a `.nettrace` file into a local folder, usually the `Downloads` folder on Windows. To view the `.nettrace` file, use Visual Studio or PrefView.

For more information, see [Use EventPipe to trace your .NET application](/dotnet/core/diagnostics/eventpipe#use-eventpipe-to-trace-your-net-application).

Expand All @@ -101,7 +99,6 @@ The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/H
In the app's project file (`.csproj`), add following properties for the duration of the investigation:

```xml
<!-- do not enable diagnostics in production, as it has a negative performance impact -->
<PropertyGroup>
<EnableDiagnostics>true</EnableDiagnostics>
<MetricsSupport>true</MetricsSupport>
Expand All @@ -122,9 +119,9 @@ Start colllecting metrics for 60 seconds by calling the `collectMetrics` JavaScr
globalThis.getDotnetRuntime(0).collectMetrics({durationSeconds: 60});
```

Call the preceding API from either a browser devoloper tools console or JavaScript code of the app.
Call the preceding API from either a browser developer tools console or JavaScript code of the app.

After the predefined period, the browser downloads a `.nettrace` file into a local folder. To view the `.nettrace` file, use Visual Studio or PrefView.
After the predefined period, the browser downloads a `.nettrace` file into a local folder, usually the `Downloads` folder on Windows. To view the `.nettrace` file, use Visual Studio or PrefView.

For more information, see [Use EventPipe to trace your .NET application](/dotnet/core/diagnostics/eventpipe#use-eventpipe-to-trace-your-net-application).

Expand Down Expand Up @@ -152,7 +149,8 @@ The following table describes permissable `<WasmPerformanceInstrumentation>` val

Your code should yield to main browser loop often to allow the trace to be collected. When executing long running loops, the internal diagnostic buffers could overflow.

**Enabling profilers and diagnostic tools has negative size and performance impacts, so don't publish an app for production with profilers enabled.**
> [!CAUTION]
> Enabling profilers and diagnostic tools has negative size and performance impacts, so don't publish an app for production with profilers enabled.

## Additional resources

Expand Down
45 changes: 32 additions & 13 deletions aspnetcore/blazor/webassembly-build-tools-and-aot.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,40 @@ This article describes the build tools for standalone Blazor WebAssembly apps an

## .NET WebAssembly build tools

The .NET WebAssembly build tools are based on [Emscripten](https://emscripten.org/), a compiler toolchain for the web platform. To install the build tools, use ***either*** of the following approaches:
The .NET WebAssembly build tools are based on [Emscripten](https://emscripten.org/), a compiler toolchain for the web platform.

* For the **ASP.NET and web development** workload in the Visual Studio installer, select the **.NET WebAssembly build tools** option from the list of optional components.
* Execute `dotnet workload install wasm-tools` in an administrative command shell.
To install the build tools as a .NET workload, use ***either*** of the following approaches:

> [!NOTE]
> .NET WebAssembly build tools for .NET 6 projects
>
> The `wasm-tools` workload installs the build tools for the latest release. However, the current version of the build tools are incompatible with existing projects built with .NET 6. Projects using the build tools that must support both .NET 6 and a later release must use multi-targeting.
>
> Use the `wasm-tools-net6` workload for .NET 6 projects when developing apps with the .NET 7 SDK. To install the `wasm-tools-net6` workload, execute the following command from an administrative command shell:
>
> ```dotnetcli
> dotnet workload install wasm-tools-net6
> ```
* For the **ASP.NET and web development** workload in the Visual Studio installer, select the **.NET WebAssembly build tools** option from the list of optional components. The option ensures the following:
* The workload is installed for the latest .NET SDK.
* When a new version of Visual Studio is released and it contains a new .NET SDK, the option installs the workload for the new SDK.
* Alternatively, execute the following command in an *administrative command shell* to install the latest workload to the latest .NET SDK available on the system:

```dotnetcli
dotnet workload install wasm-tools
```

To target a prior .NET release with a given .NET SDK, install the `wasm-tools-net{MAJOR VERSION}` workload:

* The `{MAJOR VERSION}` placeholder is replaced with the major version number of the .NET release you want to target (for example, `wasm-tools-net8` for .NET 8).
* Workloads are installed per .NET SDK. Installing the `wasm-tools` workload for one SDK doesn't make it available to other SDKs on the system.
* You must install the appropriate workload for each .NET SDK version you intend to use.

The following list shows which workload to install for each .NET SDK, depending on the apps that you plan to target. Although multiple rows may contain the same workload name, the workloads always differ slightly for each particular .NET SDK.

<!-- UPDATE 10.0 - Surface new content

* Using the .NET 10 SDK
* Targeting .NET 10 requires `wasm-tools`.
* Targeting .NET 9 requires `wasm-tools-net9`.
* Targeting .NET 8 requires `wasm-tools-net8`.

-->

* Using the .NET 9 SDK
* Targeting .NET 9 requires `wasm-tools`.
* Targeting .NET 8 requires `wasm-tools-net8`.
* Using the .NET 8 SDK: Targeting .NET 8 requires `wasm-tools`.

## Ahead-of-time (AOT) compilation

Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/fundamentals/minimal-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ The <xref:System.Delegate> arguments passed to these methods are called "route h

## Parameter binding

[!INCLUDE [](~/fundamentals/minimal-apis/includes/parameter-binding10.md)]
[!INCLUDE [](~/fundamentals/minimal-apis/includes/parameter-binding8-10.md)]

## Json+PipeReader deserialization in minimal APIs

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Reflection;

namespace CustomBindingExample;

public class CustomBoundParameter : IBindableFromHttpContext<CustomBoundParameter>
{
public string Value { get; init; } = default!;

public static ValueTask<CustomBoundParameter?> BindAsync(HttpContext context, ParameterInfo parameter)
{
// Custom binding logic here
// This example reads from a custom header
var value = context.Request.Headers["X-Custom-Header"].ToString();

// If no header was provided, you could fall back to a query parameter
if (string.IsNullOrEmpty(value))
{
value = context.Request.Query["customValue"].ToString();
}

return ValueTask.FromResult<CustomBoundParameter?>(new CustomBoundParameter
{
Value = value
});
}
}
Loading
Loading