The first of .NET 8’s Release Candidates brings Blazor's new features together in a unified project template.
.NET 8 Release Candidate 1 has shipped, and with it comes the best glimpse yet of what’s coming for .NET in November. Here are the key changes that landed with this release.
A big part of any web framework is how easy it is to get started.
.NET 8 ships with a new Blazor web app project template which combines server-side rendering with support for interactive components using Blazor Server and (optionally) Blazor WASM.
It enables enhanced navigation and form handling by default—when your users navigate between pages in your app or submit forms, the browser’s fetch API will be used (in favor of performing full page posts). Effectively this provides a “SPA-like” experience even though you’re not actually running Blazor as a SPA (single-page application).
For example, when you submit a form in a new Blazor .NET 8 app, the user’s scroll position will be retained.
There are a few new configuration options when spinning up a new project. Here are the key ones (and how they affect the resulting project).
In all cases the project uses Server-side rendering for components by default.
This is true
by default.
With this enabled, the resulting web app includes support for interactive components using Blazor Server.
dotnet new blazor --use-server true
This results in this configuration (to enable server components).
Program.cs
builder.Services.AddRazorComponents()
.AddServerComponents();
...
app.MapRazorComponents<App>()
.AddServerRenderMode();
The Counter
demo component has the RenderModeServer
attribute (it will run interactively using Blazor Server):
Counter.razor
@attribute [RenderModeServer]
False
by default.
This enables support for interactive components using Blazor WASM.
Here’s the command to use enable WASM “exclusively” (including disabling Blazor Server support, which is otherwise enabled by default).
dotnet new blazor --use-server false --use-wasm true
Program.cs
builder.Services.AddRazorComponents()
.AddWebAssemblyComponents();
...
app.MapRazorComponents<App>()
.AddWebAssemblyRenderMode();
With this enabled, your solution will have two projects—the base project plus a .Client project.
In the .Client project, Counter.razor includes the RenderModeWebAssembly
attribute, and runs interactively using Blazor WASM.
@attribute [RenderModeWebAssembly]
You can opt to enable support for interactivity using both WASM and Server.
dotnet new blazor --use-server true --use-wasm true
Program.cs
builder.Services.AddRazorComponents()
.AddServerComponents()
.AddWebAssemblyComponents();
...
app.MapRazorComponents<App>()
.AddServerRenderMode()
.AddWebAssemblyRenderMode();
With this, you’ll find your Counter
component uses the new auto render mode:
Counter.razor
@attribute [RenderModeAuto]
In this mode, Counter
will use Blazor Server initially, while the .NET runtime and app bundle is downloaded to the browser. On subsequent visits to the same component, Auto will switch to using WebAssembly instead.
One final handy option is whether to include sample pages (or not). This affects whether you get the usual Counter
, Weather
components and layout based on Bootstrap styling.
dotnet new blazor --empty
If you’re expecting to see options for enabling Auth in the project template, you might be surprised to see its omission in RC1.
According to various comments from MS employees (and open tickets in the official repo on GitHub), a new option for enabling Auth should land in RC2. With that will come several components for Auth. They will interact with the new MS Identity endpoints that you can enable when you configure your project.
Stay tuned for news of RC2 when it lands in October.
Blazor has had the same folder layout from its inception, with a single Pages folder for housing your components.
This release tweaks that structure slightly.
There is now a Components folder in the root of your project. It contains a Components/Layout folder (containing the MainLayout
and NavMenu
components).
There is also a Components/Pages folder which contains the ‘routable’ page components for the app.
App.razor is a little bit leaner in this release.
<!DOCTYPE html>
<html lang="en">
<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 rel="stylesheet" href="bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="BlazorApp51.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</head>
<body>
<Routes />
</body>
</html>
With Blazor SSR, this component acts as the entry point for your App.
This is configured in Program.cs:
app.MapRazorComponents<App>()
.AddServerRenderMode()
.AddWebAssemblyRenderMode();
Notice the new Routes
component.
<Router AppAssembly="@typeof(App).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
</Router>
This contains the Router
for your app and is the key place to go if you want to change things like the default layout.
In this example, I’m using Blazor WASM—the AdditionalAssemblies
parameter ensures .NET can route requests to components located within the separate Client project.
It’s worth taking a quick look at Components/Layout/MainLayout.razor too:
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
The notable change being that the default Blazor error UI now lives here.
If you use this new project template but want to run your entire app interactively (using WASM or Server), you can.
The trick is to specify the render mode for the HeadOutlet
and Routes
components when they’re rendered in App.razor.
<!DOCTYPE html>
<html lang="en">
<head>
...
<HeadOutlet @rendermode="@RenderMode.Server"/>
</head>
<body>
<Routes @rendermode="@RenderMode.Server"/>
<script src="_framework/blazor.web.js"></script>
</body>
</html>
With this, we’re effectively running the entire app using Blazor Server (SSR won’t be used for any of the pages).
Sometimes you might choose to locate your components in a separate project but still use static server-side rendering to render them.
A new configuration option enables that in Program.cs:
app.MapRazorComponents<App>()
.AddAdditionalAssemblies(typeof(Counter).Assembly);
This example assumes Counter
lives in a separate project (and therefore assembly).
With this, you can store your components in any assembly and still have .NET route requests to them as part of your app.
If you’re using SSR with your blazor components, you may run into a scenario where you want to refresh the page from code. You can now do this, and .NET 8 will attempt to use enhanced page navigation to perform the refresh.
This means it will use the browser’s fetch API then “patch” the DOM with the HTML that comes back (to save reloading the entire page). If it can’t use enhanced navigation for any reason, it will perform a full page refresh.
NavigationManager.Refresh();
It feels like the new QuickGrid
component has flown under the radar during .NET 8’s preview releases, with little coverage compared to other .NET 8 features.
If you’re wondering what QuickGrid
is and why you would use it, check out the official examples here:
https://aspnet.github.io/quickgridsamples/
It’s worth noting the grid is not intended as a replacement for more fully featured grids (such as Progress Telerik’s excellent Blazor Grid), but rather as a convenient and quick way to show data in your Blazor component.
Finally, as the RTM draws ever closer, .NET 8 RC1 delivers a few small but key improvements.
Check out the official release notes for the RC here. They outline some other areas of improvement, namely:
QuickGrid
and it will forward them on to the resulting table
HTML element.EditForm
field is valid using EditContext.IsValid(FieldId)
.configureRuntime
function.WasmStripILAfterAOT
option with your Blazor WASM applications to trim some code from the bundle that gets downloaded by the browser (reduces the size by 1.7% to 4.2%
in Microsoft’s tests).RC1 delivers .NET 8’s new Blazor features and provides a reliable “out-of-the-box” experience when you spin up a new Blazor web app.
You can now choose to enable interactivity using WASM or Server (or both) when creating your projects. The resulting project includes simplified base components (including the new Routes
component).
Finally, while this release doesn’t include Auth in the new template, that should be addressed in RC2.
Jon spends his days building applications using Microsoft technologies (plus, whisper it quietly, a little bit of JavaScript) and his spare time helping developers level up their skills and knowledge via his blog, courses and books. He's especially passionate about enabling developers to build better web applications by mastering the tools available to them. Follow him on Twitter here.