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
8 changes: 0 additions & 8 deletions aspnetcore/blazor/call-web-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1289,8 +1289,6 @@ Calling <xref:System.Net.Http.HttpContent.ReadAsStreamAsync%2A?displayProperty=n

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

<!-- UPDATE 10.0 - Tracking on https://github.com/dotnet/runtime/issues/97449

To opt-out of response streaming globally, use either of the following approaches:

* Add the `<WasmEnableStreamingResponse>` property to the project file with a value of `false`:
Expand All @@ -1301,12 +1299,6 @@ To opt-out of response streaming globally, use either of the following approache

* Set the `DOTNET_WASM_ENABLE_STREAMING_RESPONSE` environment variable to `false` or `0`.

............. AND REMOVE THE NEXT LINE .............

-->

To opt-out of response streaming globally, set the `DOTNET_WASM_ENABLE_STREAMING_RESPONSE` environment variable to `false` or `0`.

To opt-out of response streaming for an individual request, set <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserResponseStreamingEnabled%2A> to `false` on the <xref:System.Net.Http.HttpRequestMessage> (`request` in the following example):

```csharp
Expand Down
26 changes: 12 additions & 14 deletions aspnetcore/blazor/fundamentals/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -730,35 +730,33 @@ When a component is rendered statically (static SSR) and `NavigationManager.NotF
}
```

Two approaches for providing Not Found content for global interactive rendering:
To provide Not Found content for global interactive rendering, use a Not Found page (Razor component).

* Use a Not Found page (Razor component).
* Specify Not Found content in the [`Router` component's](xref:blazor/fundamentals/routing#route-templates) <xref:Microsoft.AspNetCore.Components.Routing.Router.NotFound%2A> property (`<NotFound>...</NotFound>` markup or by setting the `NotFound` parameter to a render fragment in C# code).

The following example uses a Not Found page (`NotFoundPage` component) to render Not Found content.
> [!NOTE]
> The Blazor project template includes a `NotFound.razor` page by default. This page automatically renders whenever `NavigationManager.NotFound` is called, making it easier to handle missing routes with a consistent user experience.

`NotFoundPage.razor`:
`NotFound.razor`:

```razor
<h1>Not Found</h1>

<p>Sorry! Nothing to show.</p>
```

Specify the `NotFoundPage` component to the `Router` component in `Routes.razor`. You might need to specify the component's namespace with an [`@using`](xref:mvc/views/razor#using) directive either at the top of the `Routes.razor` file or in an [`_Imports.razor` file](xref:blazor/components/index#component-name-class-name-and-namespace).
Assign the `NotFound` component to the router's `NotFoundPage` parameter. `NotFoundPage` supports routing that can be used across re-execution middleware, including non-Blazor middleware. If the `NotFound` render fragment is defined together with `NotFoundPage`, the page has higher priority.

In the following example, the preceding `NotFound` component is present in the app's `Pages` folder and passed to the `NotFoundPage` parameter:

```razor
<Router ...>
<Found ...>
...
<Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="@routeData" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<NotFoundPage />
</NotFound>
</Router>
```

When a component is rendered with a global interactive render mode, calling `NotFound` signals the Blazor router to render Not Found content, which is the `NotFoundPage` component:
When a component is rendered with a global interactive render mode, calling `NotFound` signals the Blazor router to render the `NotFound` component:

```razor
@page "/render-not-found-interactive"
Expand Down
92 changes: 90 additions & 2 deletions aspnetcore/blazor/performance/index.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: ASP.NET Core Blazor performance best practices
author: guardrex
description: Tips for increasing the performance of ASP.NET Core Blazor apps and avoiding common performance problems.
description: Guidance on ASP.NET Core Blazor metrics and tracing, improving app performance, and avoiding common performance problems.
monikerRange: '>= aspnetcore-3.1'
ms.author: wpickett
ms.custom: mvc
ms.date: 04/16/2025
ms.date: 06/08/2025
uid: blazor/performance/index
---
# ASP.NET Core Blazor performance best practices
Expand All @@ -24,3 +24,91 @@ Blazor is optimized for high performance in most realistic application UI scenar
Ahead-of-time (AOT) compilation compiles a Blazor app's .NET code directly into native WebAssembly for direct execution by the browser. AOT-compiled apps result in larger apps that take longer to download, but AOT-compiled apps usually provide better runtime performance, especially for apps that execute CPU-intensive tasks. For more information, see <xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation>.

:::moniker-end

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

## Metrics and tracing

Metrics and tracing capabilities help you monitor and diagnose app performance, track user interactions, and understand component behavior in production environments.

### Configuration

To enable Blazor metrics and tracing in your app, configure [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet) with the following meters and activity sources in the app's `Program` file where services are registered:

```csharp
builder.Services.ConfigureOpenTelemetryMeterProvider(meterProvider =>
{
meterProvider.AddMeter("Microsoft.AspNetCore.Components");
meterProvider.AddMeter("Microsoft.AspNetCore.Components.Lifecycle");
meterProvider.AddMeter("Microsoft.AspNetCore.Components.Server.Circuits");
});

builder.Services.ConfigureOpenTelemetryTracerProvider(tracerProvider =>
{
tracerProvider.AddSource("Microsoft.AspNetCore.Components");
});
```

### Performance meters

For more information on the following performance meters, see <xref:log-mon/metrics/built-in>.

`Microsoft.AspNetCore.Components` meter:

* `aspnetcore.components.navigation`: Tracks the total number of route changes in the app.
* `aspnetcore.components.event_handler`: Measures the duration of processing browser events, including business logic.

`Microsoft.AspNetCore.Components.Lifecycle` meter:

* `aspnetcore.components.update_parameters`: Measures the duration of processing component parameters, including business logic.
* `aspnetcore.components.render_diff`: Tracks the duration of rendering batches.

`Microsoft.AspNetCore.Components.Server.Circuits` meter:

In server-side Blazor apps, additional circuit-specific metrics include:

* `aspnetcore.components.circuit.active`: Shows the number of active circuits currently in memory.
* `aspnetcore.components.circuit.connected`: Tracks the number of circuits connected to clients.
* `aspnetcore.components.circuit.duration`: Measures circuit lifetime duration and provides total circuit count.

### Blazor tracing

For more information on the following tracing activities, see <xref:log-mon/metrics/built-in>.

The new activity tracing capabilities use the `Microsoft.AspNetCore.Components` activity source and provide three main types of tracing activities: circuit lifecycle, navigation, and event handling.

Circuit lifecycle tracing:

`Microsoft.AspNetCore.Components.CircuitStart`: Traces circuit initialization with the format `Circuit {circuitId}`.

* Tag: `aspnetcore.components.circuit.id`
* Link: HTTP activity

Navigation tracing:

`Microsoft.AspNetCore.Components.RouteChange`: Tracks route changes with the format `Route {route} -> {componentType}`.

* Tags
* `aspnetcore.components.circuit.id`
* `aspnetcore.components.route`
* `aspnetcore.components.type`
* Links
* HTTP trace
* Circuit trace

Event handling tracing:

`Microsoft.AspNetCore.Components.HandleEvent`: Traces event handling with the format `Event {attributeName} -> {componentType}.{methodName}`.

* Tags
* `aspnetcore.components.attribute.name`
* `aspnetcore.components.circuit.id`
* `aspnetcore.components.method`
* `aspnetcore.components.type`
* `error.type`
* Links
* HTTP trace
* Circuit trace
* Router trace

:::moniker-end
88 changes: 87 additions & 1 deletion aspnetcore/log-mon/metrics/built-in/includes/built-in10.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,93 @@
This article describes the metrics built-in for ASP.NET Core produced using the
<xref:System.Diagnostics.Metrics?displayProperty=nameWithType> API. For a listing of metrics based on the older [EventCounters](/dotnet/core/diagnostics/event-counters) API, see [Available counters](/dotnet/core/diagnostics/available-counters).

See [Using ASP.NET Core metrics](xref:log-mon/metrics/metrics) for information about how to collect, report, enrich, and test ASP.NET Core metrics
For information about how to collect, report, enrich, and test ASP.NET Core metrics, see <xref:log-mon/metrics/metrics>.

## `Microsoft.AspNetCore.Components`

The `Microsoft.AspNetCore.Components` metrics report information on Razor component route changes and browser events:

* [`aspnetcore.components.navigation`](#metric-aspnetcorecomponentsnavigation)
* [`aspnetcore.components.event_handler`](#metric-aspnetcorecomponentsevent_handler)

#### Metric: `aspnetcore.components.navigation`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.navigation`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentsnavigation)--> | Counter | `{route}` | Tracks the total number of route changes in the app.

Attribute | Type | Description | Examples | Presence
--- | --- | --- | --- | ---
`aspnetcore.components.type` | string | Component navigated to. | `TestComponent` | Always
`aspnetcore.components.route` | string | The component's route. | `/test-route` | Always

#### Metric: `aspnetcore.components.event_handler`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.event_handler`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentsevent_handler)--> | Histogram | `s` | Measures the duration of processing browser events, including business logic.

Attribute | Type | Description | Examples | Presence
--- | --- | --- | --- | ---
`aspnetcore.components.type` | string | Component type handling the event. | `TestComponent` | Always
`aspnetcore.components.method` | string | C# method handling the event. | `OnClick` | Always
`aspnetcore.components.attribute.name` | string | Component attribute name handling the event. | `onclick` | Always
`error.type` | string | The full name of exception type. | `System.InvalidOperationException`; `Contoso.MyException` | If an exception is thrown.

## `Microsoft.AspNetCore.Components.Lifecycle`

The `Microsoft.AspNetCore.Components.Lifecycle` metrics report information on Razor component lifecycle events:

* [`aspnetcore.components.update_parameters`](#metric-aspnetcorecomponentsupdate_parameters)
* [`aspnetcore.components.render_diff`](#metric-aspnetcorecomponentsrender_diff)

#### Metric: `aspnetcore.components.update_parameters`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.update_parameters`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentsupdate_parameters)--> | Histogram | `s` | Measures the duration of processing component parameters, including business logic.

Attribute | Type | Description | Examples | Presence
--- | --- | --- | --- | ---
`aspnetcore.components.type` | string | Component type handling the event. | `TestComponent` | Always
`error.type` | string | The full name of exception type. | `System.InvalidOperationException`; `Contoso.MyException` | If an exception is thrown.

#### Metric: `aspnetcore.components.render_diff`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.render_diff`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentsrender_diff)--> | Histogram | `s` | Tracks the duration of rendering batches.

Attribute | Type | Description | Examples | Presence
--- | --- | --- | --- | ---
`aspnetcore.components.diff.length` | int | The length of the render diff. | 50 | Always
`error.type` | string | The full name of exception type. | `System.InvalidOperationException`; `Contoso.MyException` | If an exception is thrown.

## `Microsoft.AspNetCore.Components.Server.Circuits`

The `Microsoft.AspNetCore.Components.Server.Circuits` metrics report information on server-side Blazor circuits in Blazor Server and Blazor Web Apps:

* [`aspnetcore.components.circuit.active`](#metric-aspnetcorecomponentscircuitactive)
* [`aspnetcore.components.circuit.connected`](#metric-aspnetcorecomponentscircuitconnected)
* [`aspnetcore.components.circuit.duration`](#metric-aspnetcorecomponentscircuitduration)

#### Metric: `aspnetcore.components.circuit.active`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.circuit.active`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentscircuitactive)--> | UpDownCounter | `{circuit}` | Shows the number of active circuits currently in memory.

#### Metric: `aspnetcore.components.circuit.connected`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.circuit.connected`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentscircuitconnected)--> | UpDownCounter | `{circuit}` | Tracks the number of circuits connected to clients.

#### Metric: `aspnetcore.components.circuit.duration`

Name | Instrument Type | Unit (UCUM) | Description
--- | --- | --- | ---
`aspnetcore.components.circuit.duration`<!--](https://opentelemetry.io/docs/specs/semconv/dotnet/dotnet-http-metrics/#metric-aspnetcorecomponentscircuitduration)--> | Histogram | `s` | Measures circuit lifetime duration and provides total circuit count.

## `Microsoft.AspNetCore.Hosting`

Expand Down
3 changes: 1 addition & 2 deletions aspnetcore/release-notes/aspnetcore-10.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ author: wadepickett
description: Learn about the new features in ASP.NET Core in .NET 10.
ms.author: wpickett
ms.custom: mvc
ms.date: 06/10/2025
ms.date: 6/9/2025
uid: aspnetcore-10
---
# What's new in ASP.NET Core in .NET 10
Expand All @@ -13,7 +13,6 @@ This article highlights the most significant changes in ASP.NET Core in .NET 10

This article will be updated as new preview releases are made available. For breaking changes, see [Breaking changes in .NET](/dotnet/core/compatibility/breaking-changes).


## Blazor

This section describes new features for Blazor.
Expand Down
40 changes: 25 additions & 15 deletions aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### New and updated Blazor Web App security samples

We've added and updated Blazor Web App security samples cross-linked in the following articles:
We've added and updated the Blazor Web App security samples linked in the following articles:

* <xref:blazor/security/blazor-web-app-oidc>
* <xref:blazor/security/blazor-web-app-entra>
Expand Down Expand Up @@ -110,10 +110,6 @@ In prior Blazor releases, response streaming for <xref:System.Net.Http.HttpClien

This is a breaking change because calling <xref:System.Net.Http.HttpContent.ReadAsStreamAsync%2A?displayProperty=nameWithType> for an <xref:System.Net.Http.HttpResponseMessage.Content%2A?displayProperty=nameWithType> (`response.Content.ReadAsStreamAsync()`) returns a `BrowserHttpReadStream` and no longer a <xref:System.IO.MemoryStream>. `BrowserHttpReadStream` doesn't support synchronous operations, such as `Stream.Read(Span<Byte>)`. If your code uses synchronous operations, you can opt-out of response streaming or copy the <xref:System.IO.Stream> into a <xref:System.IO.MemoryStream> yourself.

<!-- UNCOMMENT FOR PREVIEW 5 ...
Waiting on https://github.com/dotnet/runtime/issues/97449
... and update the Call web API article Line 983

To opt-out of response streaming globally, use either of the following approaches:

* Add the `<WasmEnableStreamingResponse>` property to the project file with a value of `false`:
Expand All @@ -124,12 +120,6 @@ To opt-out of response streaming globally, use either of the following approache

* Set the `DOTNET_WASM_ENABLE_STREAMING_RESPONSE` environment variable to `false` or `0`.

............. AND REMOVE THE NEXT LINE .............

-->

To opt-out of response streaming globally, set the `DOTNET_WASM_ENABLE_STREAMING_RESPONSE` environment variable to `false` or `0`.

To opt-out of response streaming for an individual request, set <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserResponseStreamingEnabled%2A> to `false` on the <xref:System.Net.Http.HttpRequestMessage> (`requestMessage` in the following example):

```csharp
Expand Down Expand Up @@ -387,8 +377,6 @@ Calling <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A?di

Code that relied on <xref:Microsoft.AspNetCore.Components.NavigationException> being thrown should be updated. For example, in the default Blazor Identity UI, the `IdentityRedirectManager` previously threw an <xref:System.InvalidOperationException> after calling `RedirectTo` to ensure it wasn't invoked during interactive rendering. This exception and the [`[DoesNotReturn]` attributes](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute) should now be removed.

<!-- HOLD FOR PREVIEW 5

To revert to the previous behavior of throwing a <xref:Microsoft.AspNetCore.Components.NavigationException>, set the following <xref:System.AppContext> switch:

```csharp
Expand All @@ -397,8 +385,6 @@ AppContext.SetSwitch(
isEnabled: true);
```

-->

### Not Found responses using `NavigationManager` for static SSR and global interactive rendering

The <xref:Microsoft.AspNetCore.Components.NavigationManager> now includes a `NotFound` method to handle scenarios where a requested resource isn't found during static server-side rendering (static SSR) or global interactive rendering:
Expand All @@ -412,3 +398,27 @@ Per-page/component rendering support is planned for Preview 5 in June, 2025.
You can use the `NavigationManager.OnNotFound` event for notifications when `NotFound` is invoked.

For more information and examples, see <xref:blazor/fundamentals/routing?view=aspnetcore-10.0#not-found-responses>.

### Blazor router has a `NotFoundPage` parameter

Blazor now provides an improved way to display a "Not Found" page when navigating to a non-existent page. You can specify a page to render when `NavigationManager.NotFound` by passing a page type to the `Router` component using the `NotFoundPage` parameter. This approach is recommended over the previous `NotFound` fragment, as it supports routing, works across code re-execution middleware, and is compatible even with non-Blazor scenarios. If both a `NotFound` fragment and `NotFoundPage` are defined, the page specified by `NotFoundPage` takes priority.

```razor
<Router AppAssembly="@typeof(Program).Assembly" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="@routeData" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>This content is ignored because NotFoundPage is defined.</NotFound>
</Router>
```

The Blazor project template now includes a `NotFound.razor` page by default. This page automatically renders whenever `NavigationManager.NotFound` is called in your app, making it easier to handle missing routes with a consistent user experience.

For more information, see <xref:blazor/fundamentals/routing#not-found-responses>.

### Metrics and tracing

This release introduces comprehensive metrics and tracing capabilities for Blazor apps, providing detailed observability of the component lifecycle, navigation, event handling, and circuit management.

For more information, see <xref:blazor/performance/index#metrics-and-tracing>.