Blazor updates for .NET 6 using Visual Studio 2022
Published: Thursday 16 September 2021
Blazor is having some significant updates in .NET 6, and we will have a look at four new features which are available to try out in Visual Studio 2022.
Update #1: Preserving prerendering state
Prerendering was one of the new features for Blazor in .NET 5. This allows a Blazor WebAssembly application to be loaded on the server before being present to the client.
Viewing the source code of a Blazor WebAssembly application
If we wish to have SEO support for our Blazor Wasm application, this can present a problem. This is because a search crawler would have to render the WebAssembly part of our application to crawl the application's content.
The problem with .NET 5
However, this posed a problem in .NET 5. We were unable to store any data we had prerendered from the host and transfer it to the client. That means that we would have to load in the same data with the host and the client.
PersistentComponentState.
<persist-component-state /> tag to our _Host.cshtml file.
<!-- Host.cshtml -->
@page
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_Layout";
}
<component type="typeof(RoundTheCode.BlazorDotNet6.Wasm.App)" render-mode="WebAssemblyPrerendered" />
<script src="_framework/blazor.webassembly.js"></script>
<persist-component-state />
From there, we can inject our PersistentComponentState instance into our Razor component.
<!-- NoteListingComponent.razor -->
@using RoundTheCode.BlazorDotNet6.Wasm.Models
@using System.Diagnostics
@inject PersistentComponentState ApplicationState
Now, our Blazor Wasm application is a note listing application where we can add and store notes.
OnInitializedAsync method, we add a new event handler to the OnPersisting event handler. This stores our data as JSON. In this instance, it's our default notes that are being stored.
OnInitializedAsync method, it will use the data stored in the application state and will mean that we don't have to create the default notes again.
<!-- NoteListingComponent.razor -->
@using RoundTheCode.BlazorDotNet6.Wasm.Models
@using System.Diagnostics
@implements IDisposable
@inject PersistentComponentState ApplicationState
@page "/"
...
@code {
...
protected override async Task OnInitializedAsync()
{
ApplicationState.RegisterOnPersisting(() => StoreNotes());
if (ApplicationState.TryTakeFromJson<Note[]>("Notes", out var storedNotes))
{
Notes = storedNotes.ToList();
}
else
{
Notes = new List<Note>();
Notes.Add(new Note("Hello there", DateTime.UtcNow));
Notes.Add(new Note("How are you doing?", DateTime.UtcNow));
}
await base.OnInitializedAsync();
}
...
private Task StoreNotes()
{
ApplicationState.PersistAsJson("Notes", Notes);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
}
}
Update #2: Querystring component parameters
With Blazor in .NET 6, there is a nice simple change where a parameter can be supplied from a querystring parameter.
[Parameter] attribute, and then add a [SupplyParameterFromQuery] attribute.
[SupplyParameterFromQuery] attribute if we wish to override this.
Message querystring parameter in the URL, it would be stored in the CustomMessage property. This is because the CustomMessage property has a [SupplyParameterFromQuery] attribute, with the Name parameter set as "Message".
<!-- NoteListingComponent.razor -->
@using RoundTheCode.BlazorDotNet6.Wasm.Models
@using System.Diagnostics
@implements IDisposable
@inject ComponentApplicationState ApplicationState
@page "/"
@if(!string.IsNullOrWhiteSpace(CustomMessage))
{
<p>My Custom Message: @CustomMessage</p>
}
...
@code {
...
[Parameter]
[SupplyParameterFromQuery(Name = "Message")]
public string CustomMessage { get; set; }
...
}
Update #3: Modify page title from a Razor component
With Blazor in .NET 6, we can add a page title into a Razor component.
<title> tag from our layout, and replace it with a component. For the component, we will pass in a type of HeadOutlet.
WebAssemblyPrerendered.
<!-- Host.cshtml -->
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using Microsoft.AspNetCore.Components.Web;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="RoundTheCode.BlazorOnClick.styles.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
</head>
<body>
@RenderBody()
</body>
</html>
From there, we can use the <PageTitle> tag to insert a dynamic page title into our note listing component.
<!-- NoteListingComponent.razor -->
...
@page "/"
<PageTitle>Viewing @((Notes?.Any() ?? false) ? Notes.Count() : 0) notes</PageTitle>
...
Update #4: Error boundaries
Our final update is looking at error boundaries.
<!-- NoteViewComponent.razor -->
@using RoundTheCode.BlazorDotNet6.Wasm.Models
@if (Note != null)
{
<li class="@ClassName" @onmouseover="@OnMouseOver" @onmouseout="@OnMouseOut">
<span>@Note.Message</span>
<span>Created: @Note.Created.ToUniversalTime().ToString("ddd d MMM yyyy HH:mm:ss")</span>
<button type="submit" @onclick="OnDeleteNote">Delete</button>
</li>
}
@code {
...
protected override void OnInitialized()
{
if (Note?.Message.StartsWith("a") ?? false) {
throw new Exception("Note message shouldn't start with a.");
}
}
}
So how do we allow to show an error message for that particular note?
<ErrorBoundary> tag allows us to do that. Inside this tag, we can call the <ChildContent> tag. Assuming no exceptions are called, the content inside the <ChildContent> tag will be rendered to the application.
<ErrorContent> tag. With the <ErrorContent> tag, we can supply a Context attribute which has the exception instance.
<ErrorBoundary> tag every time the NoteViewComponent Razor component is called.
<!-- NoteListingComponent.razor -->
@page "/"
...
<div class="col-6">
<h2>Your saved notes</h2>
@if (Notes?.Any() ?? false)
{
<ul>
@foreach (var note in Notes)
{
<ErrorBoundary>
<ChildContent>
<NoteViewComponent Note="@note" OnDeleteNote="@((e) => OnDeleteNote(e, note))"></NoteViewComponent>
</ChildContent>
<ErrorContent Context="ex">
<li>Message has the following error: @ex.Message</li>
</ErrorContent>
</ErrorBoundary>
}
</ul>
}
...
The exception is exclusive to the note throwing the exception which we can see in the image below:
Using the ErrorBoundary tag in Blazor for .NET 6.
See these Blazor .NET 6 updates in action
Check out our video where we demonstrate these updates using a .NET 6 Blazor application.
ComponentApplicationState has been changed to PersistentComponentState in .NET 6 RC2. This has been updated in the article and the code example, but not the video.In addition, download our code example to download our .NET 6 Blazor app, and see these updates in action.
Other .NET 6 reading
This continues our .NET 6 updates, where we also took a look at ASP.NET Core's new features, and C# 10 changes. These updates show that Microsoft is taking a keen interest in Blazor as it looks to become a serious competitor with the popular JavaScript frameworks out there.
Related articles
EF Core 6 new features and changes for .NET 6
Check out what's new in EF Core 6. As part of .NET 6, Entity Framework Core introduced migration bundles and support for temporal tables.
C# 10: New features and examples that are not in C# 9
Looking at new C# features in C Sharp 10, which is due to be launched alongside .NET 6 and Visual Studio 2022.