Render Blazor WASM components in your existing MVC/Razor Pages applications

October 13, 2020 · 4 minute read · Tags: blazor | prerendering

My recent post shows how to prerender a Blazor WASM application so your users aren’t left hanging while they wait for the application to load.

This is great for speeding up your Blazor WASM app’s initial load time but .NET 5’s new render modes also open up another compelling door.

You can prerender individual Blazor WASM components on any of your Razor pages (or views).

If you have an established application you may well want to start by incrementally migrating parts of the UI to Razor components (or adding new features as components while you find your Blazor feet)

The key to unlocking this is the component tag helper and a new render mode called WebAssemblyPrerendered.

Say you have a standard Razor Pages application and a Blazor WASM project, you can add a reference from the Razor Pages app to the Blazor WASM project, then include a component on any given Razor Page.

Index.cshtml

@using ExampleApp.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered"/>

<script src="_framework/blazor.webassembly.js"></script>

ExampleApp.Client refers to the Blazor WASM project in this scenario.

WebAssemblyPrerendered is a new render mode, included in .NET 5 RC1 and later, which effectively says this component should be rendered on the server and returned as static HTML.

It means there’s virtually no delay when someone access this page and they’ll see the component (counter in this case) immediately.

The component won’t be ‘interactive’ right away, but will spring into life once the browser finishes downloading and/or loading any files it needs (.NET runtime, your app’s dlls etc).

Here it is in action:

Render individual components - step by step

Here’s the exact process to make this work.

First, create a new (or use an existing) ASP.NET Core Razor Pages application.

Add this PackageReference (to the Razor Pages app).

dotnet add package Microsoft.AspNetCore.Components.WebAssembly.Server --prerelease

The --prerelease flag makes sure you get the latest RC of .NET 5 (Release Candidate 1 at the time of writing).

Head over to Startup.cs and add a call to app.UseBlazorFrameworkFiles() (in the Configure method)

Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{   
   // other code

    app.UseHttpsRedirection();

    app.UseBlazorFrameworkFiles(); // add this

    app.UseStaticFiles();

    // other code
}

With that done, all that’s left is to reference the blazor WASM javascript file and the component you wish to render.

Index.cshtml (or any other Page/View)

@using ExampleApp.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered"/>

<script src="_framework/blazor.webassembly.js"></script>

At this point you’ll need to reference the Blazor project from your Razor Pages project.

If you plan on using this a lot it might also be worth moving that <script> reference over to your shared layout page so you don’t have to add it to every individual page/view.

Gotcha - your WASM app expects an #app div

When you try this you will almost certainly get an error along these lines in the browser console:

blazor.webassembly.js:1 Microsoft.JSInterop.JSException: Could not find any element matching selector ‘#app’

This is because your Blazor WASM app expects to load itself into an #app element and complains when it can’t find one.

You can prevent this from happening if you head over to the client (Blazor WASM) project, and remove this line from Program.cs.

builder.RootComponents.Add<App>("#app");

With that removed Blazor will no longer attempt to render your entire app using the #app div, leaving you free to render the components you wish via your Razor Pages.

OnInitializedAsync is called twice

One thing to watch here, as I outlined in my previous article on prerendering is that your component is rendered twice when prerendering; once on the server, to generate static HTML which is returned to the browser, then again on the client (in the browser) to actually load up your component and make it ‘dynamic’.

Consequently your OnInitialized override (or its async equivalent) will be invoked twice.

Microsoft are aware of this issue and are exploring options. In the meantime, check out my previous articles for suggestions on how to mitigate the effects of this.

In summary

It’s much easier with .NET 5 to start using Blazor WASM components in your existing applications.

This opens the door to incrementally migrating towards Blazor WASM. You can either migrate existing logic/views, or opt to use Razor components for new features (where it makes sense to do so).

For the most part prerendering WASM components makes this fairly seamless for your users but there is a niggling issue with OnInitialized being invoked twice at the moment which causes your UI to ‘flicker’ when the second render takes place.

Hopefully this is a short term issue and solutions (or workarounds) will be found in due course.

Join the Practical ASP.NET Newsletter

Ship better Blazor apps, faster. One practical tip every Tuesday.

I respect your email privacy. Unsubscribe with one click.

    Next up

    Finally! Improved Blazor Server reconnection UX
    .NET 9 changes how your Blazor Server app behaves when server connection is lost
    .NET 9 improves JavaScript module importing for Blazor
    .NET 9 ensures your users always get the latest version of your JS modules
    How to use .NET 9 to ensure users always get the latest version of your stylesheets
    .NET 9 changes how static files are served, and it solves a long-standing problem