Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hosting models/render modes & What's New 8.0 #30279

Merged
merged 45 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
21e9d90
Hosting models/render modes 8.0
guardrex Sep 8, 2023
78b2134
Updates
guardrex Sep 8, 2023
5bacb4e
Updates
guardrex Sep 8, 2023
24748a5
Updates
guardrex Sep 8, 2023
8f010cd
Apply suggestions from code review
guardrex Sep 8, 2023
aa616e1
Updates
guardrex Sep 8, 2023
b8408e4
Updates
guardrex Sep 8, 2023
ca9337a
Apply suggestions from code review
guardrex Sep 8, 2023
b789632
Updates
guardrex Sep 8, 2023
26820e3
Updates
guardrex Sep 9, 2023
ca46d00
Apply suggestions from code review
guardrex Sep 9, 2023
7e629ee
Updates
guardrex Sep 9, 2023
2c5803a
Updates
guardrex Sep 9, 2023
25431ab
Apply suggestions from code review
guardrex Sep 9, 2023
8828afe
Updates
guardrex Sep 9, 2023
c657683
Updates
guardrex Sep 9, 2023
7f37316
Updates
guardrex Sep 9, 2023
ca082c8
Updates
guardrex Sep 9, 2023
176d1f8
Updates
guardrex Sep 9, 2023
f015c06
Apply suggestions from code review
guardrex Sep 9, 2023
d6c0e00
Updates
guardrex Sep 9, 2023
80f96dd
Updates
guardrex Sep 9, 2023
1e4adc7
Update aspnetcore/blazor/fundamentals/render-modes.md
guardrex Sep 9, 2023
c5e97dd
Update aspnetcore/blazor/fundamentals/render-modes.md
guardrex Sep 9, 2023
7a5fc94
Updates
guardrex Sep 9, 2023
63a27f5
Apply suggestions from code review
guardrex Sep 9, 2023
ecc270b
Updates
guardrex Sep 9, 2023
61e5a48
Apply suggestions from code review
guardrex Sep 10, 2023
bdf1ecf
Updates
guardrex Sep 10, 2023
f8ca164
Apply suggestions from code review
guardrex Sep 10, 2023
dbc875b
Updates
guardrex Sep 10, 2023
f638409
Updates
guardrex Sep 10, 2023
4b0b577
Updates
guardrex Sep 10, 2023
25c035b
Updates
guardrex Sep 10, 2023
05ff757
Updates
guardrex Sep 10, 2023
60146d7
Updates
guardrex Sep 10, 2023
0481997
Updates
guardrex Sep 11, 2023
ef1dd6b
Updates
guardrex Sep 11, 2023
7956015
Apply suggestions from code review
guardrex Sep 11, 2023
ea40f89
Updates
guardrex Sep 11, 2023
a5d7ffe
Update aspnetcore/release-notes/aspnetcore-8.0.md
guardrex Sep 11, 2023
2b1d98d
Update aspnetcore/release-notes/aspnetcore-8.0.md
guardrex Sep 11, 2023
de8e747
Updates
guardrex Sep 11, 2023
6cb1b53
Update aspnetcore/release-notes/aspnetcore-8.0.md
guardrex Sep 11, 2023
30ebc41
Apply suggestions from code review
guardrex Sep 11, 2023
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
42 changes: 40 additions & 2 deletions aspnetcore/blazor/fundamentals/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,33 @@ The following is an example counter component and part of an app created from a

`Counter.razor`:

<!-- UPDATE 8.0 Probably switch over to the BWA example when the BWA snippet sample goes up -->
:::moniker range=">= aspnetcore-8.0"

```razor
@page "/counter"
@attribute [RenderModeServer]

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

:::moniker range=">= aspnetcore-7.0"
@code {
private int currentCount = 0;

private void IncrementCount()
{
currentCount++;
}
}
```

:::moniker-end

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

:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/Counter.razor":::

Expand All @@ -66,11 +90,25 @@ The following is an example counter component and part of an app created from a

The preceding `Counter` component:

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

* Sets its route with the `@page` directive in the first line.
* Sets the component's render mode to the [Blazor Server hosting model](xref:blazor/hosting-models#blazor-server) with `@attribute [RenderModeServer]`. Render modes are fully explained and demonstrated in the next article, <xref:blazor/fundamentals/render-modes>.
* Sets its page title and heading.
* Renders the current count with `@currentCount`. `currentCount` is an integer variable defined in the C# code of the `@code` block.
* Displays a button to trigger the `IncrementCount` method, which is also found in the `@code` block and increases the value of the `currentCount` variable.

:::moniker-end

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

* Sets its route with the `@page` directive in the first line.
* Sets its page title and heading.
* Renders the current count with `@currentCount`. `currentCount` is an integer variable defined in the C# code of the `@code` block.
* Displays a button to trigger the `IncrementCount` method, which is also found in the `@code` block and increases the value of the `currentCount` variable.

:::moniker-end

## Document Object Model (DOM)

References to the *Document Object Model* use the abbreviation *DOM*.
Expand Down
295 changes: 295 additions & 0 deletions aspnetcore/blazor/fundamentals/render-modes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
---
title: ASP.NET Core Blazor render modes
author: guardrex
description: Learn about Blazor render modes and how to apply them in Blazor Web Apps.
monikerRange: '>= aspnetcore-8.0'
ms.author: riande
ms.custom: mvc
ms.date: 09/08/2023
uid: blazor/fundamentals/render-modes
---
# ASP.NET Core Blazor render modes

This article explains how to establish hosting models for rendered Razor components in Blazor Web Apps, either at compile time or runtime.

## Render modes

Every component in a Blazor Web App adopts a *render mode* to determine the hosting model that it uses, where it's rendered, and whether or not it's interactive with C# code.

The following table shows the four potential render mode scenarios for rendering Razor components in a Blazor Web App. The render mode attributes in the *Render mode attribute* column are applied to components with the [`@attribute` Razor directive](xref:mvc/views/razor#attribute). Later in this article, examples are shown for each render mode scenario.

Scenario | Render mode attribute | Hosting model | Render location | Interactive
----------------------------- | :-----------------------: | :---------------------------------------: | :-----------------: | :---------:
Statically-rendered | None | None | Server | ❌
*Server-side rendering (SSR)* | `[RenderModeServer]` | Blazor Server | Server | ✔️
*Client-side rendering (CSR)* | `[RenderModeWebAssembly]` | Blazor WebAssembly | Client | ✔️
Determined at runtime | `[RenderModeAuto]` | Blazor Server,<br>then Blazor WebAssembly | Server, then client | ✔️

<!-- HOLD for final commit - We'll use accessible markup for the ❌ and ✔️:
<span aria-hidden="true">❌</span><span class="visually-hidden">No</span>
<span aria-hidden="true">✔️</span><span class="visually-hidden">Yes</span>
-->

The following examples demonstrate setting the component's render mode with a few basic Razor component features.

To test the render mode behaviors locally, you can place the following components in an app created from the *Blazor Web App* project template. When you create the app, select the checkboxes (Visual Studio) or apply the CLI options (.NET CLI) to enable both server-side and client-side interactivity. For guidance on how to create a Blazor Web App, see <xref:blazor/tooling>.

### Statically-rendered on the server without user interactivity

In the following example, there's no designation for the component's render mode. Therefore, the component is *statically rendered* on the server. The button isn't interactive and doesn't call the `UpdateMessage` method when selected. The value of `message` doesn't change, and the component isn't re-rendered.

If using the following component locally in a Blazor Web App, place the component in the server-side project's `Components/Pages` folder. The server-side project is the solution's project with a name that doesn't end in `.Client`. When the app is running, navigate to `/render-mode-1` in the browser's address bar.

`RenderMode1.razor`:

```razor
@page "/render-mode-1"

<button @onclick="UpdateMessage">Click me</button> @message

@code {
private string message = "Not clicked yet.";

private void UpdateMessage()
{
message = "Somebody clicked me!";
}
}
```

> [!NOTE]
> The anatomy of a basic Razor component is fully explained in the <xref:blazor/fundamentals/index> article. Project structure for apps created by a Blazor template are described in the <xref:blazor/project-structure> article. Detailed components coverage is found in the *Components* articles later in the documentation.

### Server-side rendering (SSR)

Server-side rendering (SSR) results in rendering a component on the server with user interactivity.

In the following example, the render mode is set to use the Blazor Server hosting model with `@attribute [RenderModeServer]`. Therefore, the component is rendered server-side with server-side interactivity over a SignalR connection. The button calls the `UpdateMessage` method when selected. The value of `message` changes, and the component is re-rendered to update the message in the UI.

If using the following component locally in a Blazor Web App, place the component in the server-side project's `Components/Pages` folder. The server-side project is the solution's project with a name that doesn't end in `.Client`. When the app is running, navigate to `/render-mode-2` in the browser's address bar.

`RenderMode2.razor`:

```razor
@page "/render-mode-2"
@attribute [RenderModeServer]

<button @onclick="UpdateMessage">Click me</button> @message

@code {
private string message = "Not clicked yet.";

private void UpdateMessage()
{
message = "Somebody clicked me!";
}
}
```

### Client-side rendering (CSR)

Client-side rendering (CSR) results in rendering a component on the client with user interactivity.

In the following example, the render mode is set to use the Blazor WebAssembly hosting model with `@attribute [RenderModeWebAssembly]`. Therefore, the component is rendered client-side with interactivity. The button calls the `UpdateMessage` method when selected. The value of `message` changes, and the component is re-rendered to update the message in the UI.

If using the following component locally in a Blazor Web App, place the component in the client-side project's `Pages` folder. The client-side project is the solution's project with a name that ends in `.Client`. When the app is running, navigate to `/render-mode-3` in the browser's address bar.

`RenderMode3.razor`:

```razor
@page "/render-mode-3"
@attribute [RenderModeWebAssembly]

<button @onclick="UpdateMessage">Click me</button> @message

@code {
private string message = "Not clicked yet.";

private void UpdateMessage()
{
message = "Somebody clicked me!";
}
}
```

### Render mode determined at runtime

The render mode can be determined at runtime. The component is initially rendered server-side with interactivity (SSR) using the Blazor Server hosting model. After the Blazor bundle is downloaded to the client and the .NET client-side runtime activates, the component adopts the Blazor WebAssembly hosting model for client-side rendering and interactivity (CSR).

In the following example, the component is interactive throughout the process. The button calls the `UpdateMessage` method when selected. The value of `message` changes, and the component is re-rendered, either server-side or client-side, to update the message in the UI.

If using the following component locally in a Blazor Web App, place the component in the client-side project's `Pages` folder. The client-side project is the solution's project with a name that ends in `.Client`. When the app is running, navigate to `/render-mode-4` in the browser's address bar.

`RenderMode4.razor`:

```razor
@page "/render-mode-4"
@attribute [RenderModeAuto]

<button @onclick="UpdateMessage">Click me</button> @message

@code {
private string message = "Not clicked yet.";

private void UpdateMessage()
{
message = "Somebody clicked me!";
}
}
```

## Render mode propagation
Copy link
Member

@danroth27 danroth27 Sep 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a few more example to this section?:

  1. A parent component with two child sibling component that use different render modes
  2. A negative case of a child component that tries to use a different interactive render mode than its parent, which results in an error
  3. A parent component with an interactive child component that takes a parameter that is serializable (works)
  4. A negative case of an interactive child component that has a non-serializable component parameter, like child content or a render fragment, which results in an error. Show that you can sometimes work around this by wrapping the child component in another component that doesn't have the parameter. This is what we do in the Blazor Web App template with the Routes component to wrap the Blazor Router.


Render modes propagate down the component hierarchy. Consider the following `SharedMessage` component for use in other components that doesn't indicate a render mode.

`SharedMessage.razor`:

```razor
<button @onclick="UpdateMessage">Click me</button> @message

@code {
private string message = "Not clicked yet.";

private void UpdateMessage()
{
message = "Somebody clicked me!";
}
}
```

If the `SharedMessage` component is placed in a statically-rendered parent component, the `SharedMessage` component is also rendered statically and isn't interactive. The button doesn't call `UpdateMessage`, and the message isn't updated.

`PassedRenderMode1.razor`:

```razor
@page "/passed-render-mode-1"

<SharedMessage />
```

If the `SharedMessage` component is placed in a server-side rendered (SSR) component, it adopts SSR. The `SharedMessage` component is interactive over a SignalR connection to the client. The button calls `UpdateMessage`, and the message is updated.

`PassedRenderMode2.razor`:

```razor
@page "/passed-render-mode-2"
@attribute [RenderModeServer]

<SharedMessage />
```

If the `SharedMessage` component is placed in a client-side rendered (CSR) component, it adopts CSR. The `SharedMessage` component is interactive on the client with the .NET WebAssembly-based runtime. The button calls `UpdateMessage`, and the message is updated.

`PassedRenderMode3.razor`:

```razor
@page "/passed-render-mode-3"
@attribute [RenderModeWebAssembly]

<SharedMessage />
```

If the `SharedMessage` component is placed in a dynamically-rendered component, where the render mode is determined at runtime, it adopts SSR initially, then CSR after the component and Blazor bundle are downloaded and the .NET runtime activates on the client. The component is interactive. The button calls `UpdateMessage`, and the message is updated.

`PassedRenderMode4.razor`:

```razor
@page "/passed-render-mode-4"
@attribute [RenderModeAuto]

<SharedMessage />
```

## Set the render mode for the entire app

To set the render mode for the entire app, indicate the render mode at the highest level component in the app's component hierarchy, typically the `Routes` component (`Components/Routes.razor`) for apps based on the Blazor Web App project template:

```razor
@attribute {RENDER MODE}

<Router AppAssembly="@typeof(App).Assembly" ...>
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
</Router>
```

In the preceding example, the `{RENDER MODE}` placeholder is the render mode (`[RenderModeServer]`, `[RenderModeWebAssembly]`, or `[RenderModeAuto]`). The render mode propagates down the component hierarchy to all of the components in the app.

## API extensions that support components in Blazor Web Apps

The following extensions are automatically applied to apps created from the [*Blazor Web App* project template](xref:blazor/tooling) when either or both of server-side component interactivity and client-side component interactivity are enabled during app creation. Individual components are still required to declare their render mode per the [*Render modes*](#render-modes) section after the component services and endpoints are configured in the app's `Program` file.

Services for Razor components are added by calling <xref:Microsoft.Extensions.DependencyInjection.RazorComponentsServiceCollectionExtensions.AddRazorComponents%2A>.

Component builder extensions:

* <xref:Microsoft.Extensions.DependencyInjection.RazorComponentsBuilderExtensions.AddServerComponents%2A> adds services to support rendering interactive server components.
* `AddWebAssemblyComponents` adds services to support rendering interactive WebAssembly components.

<!-- UPDATE 8.0 HOLD
<xref:Microsoft.Extensions.DependencyInjection.WebAssemblyRazorComponentsBuilderExtensions.AddWebAssemblyComponents%2A>
-->

<xref:Microsoft.AspNetCore.Builder.RazorComponentsEndpointRouteBuilderExtensions.MapRazorComponents%2A> discovers available components and specifies the root component for the app, which by default is the `App` component (`App.razor`).

Endpoint convention builder extensions:

* <xref:Microsoft.AspNetCore.Builder.RazorComponentEndpointConventionBuilder.AddServerRenderMode%2A> configures the Server render mode for the app.
* `AddWebAssemblyRenderMode` configures the WebAssembly render mode for the app.

<!-- UPDATE 8.0 HOLD
<xref:Microsoft.AspNetCore.Builder.WebAssemblyRazorComponentsEndpointConventionBuilderExtensions.AddWebAssemblyRenderMode%2A>
-->

Example 1: The following `Program` file API adds services and a render mode for Razor components with only server-side rendering (SSR) support:

```csharp
...

builder.Services.AddRazorComponents()
.AddServerComponents();


...

app.MapRazorComponents<App>()
.AddServerRenderMode();

...
```

Example 2: The following `Program` file API adds services and a render mode for Razor components with only client-side rendering (CSR) support:

```csharp
...

builder.Services.AddRazorComponents()
.AddWebAssemblyComponents();

...

app.MapRazorComponents<App>()
.AddWebAssemblyRenderMode();

...
```

Example 3: The following `Program` file API adds services and render modes for Razor components with both SSR and CSR support:

```csharp
...

builder.Services.AddRazorComponents()
.AddServerComponents()
.AddWebAssemblyComponents();

...

app.MapRazorComponents<App>()
.AddServerRenderMode()
.AddWebAssemblyRenderMode();

...
```
Loading