In this article, I'll show you how you can add Blazor-based pages to an existing Razor Pages app.
Foreword
Blazor will go gold in two weeks . Many things in the project are still subject to quite dramatic changes, and the latest Preview 9 has made the interaction between Razor Pages and Blazor components much more difficult: it is no longer possible to pass parameters from a Razor page to a Blazor component using
Html.RenderComponentAsync
. This may change in the future, but it is likely that in .NET Core 3.0 it will appear with this limitation.
If you still want to enhance your existing Razor Pages app with Blazor magic, one solution is to completely create your pages in Blazor. In this article, I'll show you how you can add Blazor Pages to an existing Razor Pages app, where parts of the app are built using Razor Pages and others using Blazor Pages. The layout is the same for both types of pages .
Step one: support for Blazor
So, we have an existing Razor Pages application that has been converted to .NET Core 3.
First, you need to add Blazor support to your application. This support will allow you to render Blazor components from a Razor page. The official documentation walks you through the process completely, but here's a quick rundown.
Startup.cs:
We need to add
Services.AddServerSideBlazor
to ConfigureServices
and endpoints.MapBlazorHub
in Configure
:
_Layout.cshtml : The Blazor
JS library is needed to connect Blazor on the server side. It can be added to
_Layout.cshtml
:
?
<script src="_framework/blazor.server.js"></script>
_Imports.razor:
We also need a new file named
_Imports.razor
. It must be added to the Pages folder:
_Imports.razor
used to set the using statements for your Blazor components. You can start with the following
:?
@using System.Net.Http
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.JSInterop
@using Microsoft.AspNetCore.Components.Web
And that's all . Our app now supports Blazor. Can we verify this by copying the classic Counter component into our application
?
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
}
And edit
Privacy.cshtml
to include the Counter component:
<a href="https://mikaelkoskinen.net/post/combining-razor-blazor-pages-single-asp-net-core-3-application#">?</a>
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
<component>@(await Html.RenderComponentAsync<Counter>(RenderMode.Server))</component>
Now, when we launch the application, a working Counter should appear on our page:
In the next part of this article, I'll show you how you can modify your Razor Pages application so that instead of just adding components to existing pages, you can create complete Blazor pages.
Step two: support for Blazor Pages
Our Blazor component defines a route
โ/counterโ
:
But following it doesn't work:
Our goal is to get routing to Blazor pages to work. And we want Blazor pages to use the same layout as Razor pages. We'll need a few things to do this, starting with the Router .
App.razor:
Create a new file
App.razor
in the folderPages
:
Router component is defined in
App.razor
:
?
@using Microsoft.AspNetCore.Components.Routing
<Router AppAssembly="typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="routeData"/>
</Found>
<NotFound>
<h1>Page not found</h1>
<p>Sorry, but there's nothing here!</p>
</NotFound>
</Router>
Router automatically scans all Blazor components using the page directive and adds routes to them.
_Host.cshtml:
We also need a page to host the Blazor pages. It can be called whatever you want, but Blazor templates are used by default
_Host.cshtml
, which is fine for us (as well as any other). In _Host.cshtml
we can define a layout, which in our case will be the same as for Razor pages.
_Host.cshtml
contains the call Html.RenderComponentAsync
:
?
@page "/blazor"
@{
Layout = "_Layout";
}
<app>
@(await Html.RenderComponentAsync<App>(RenderMode.Server))
</app>
Startup.cs:
And finally, a small addition to the method
Configure Startup.cs
. Earlier we added MapBlazorHub
, and now we need to add a call MapFallbackToPage
pointing to the new one _Host.cshtml
:
And that's it! Now we just need to test our setup. Add a Blazor Page Counter (Counter) to your layout by editing
Pages/Shared/_Layout.cshtml
:
When we launch the app, we see a working Blazor page in our Razor Pages app:
And we didn't break support for adding Blazor components to Razor Pages:
Notes
A couple of things to note:
- Blazor routes only work when they point to the root. If โ/ counterโ is changed to, for example, the
โ/products/counterโ
page will not be able to load the required oneblazor.server.js
. We'll get a 404 instead. It should be possible to change the script tag so that it can load the required script regardless of location, but that seems to have changed from pre-8 to pre-9 and I couldn't get it to work. Here is a 404 screenshot showing the problem: - If you manage to load the script, you will probably run into the same problems with Blazor hub: scripts try to find hub in / products / blazor instead of blazor. To work around this, you can manually initiate a connection between the server and browser:
?
<script src="~/_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({
configureSignalR: function (builder) {
builder.withUrl('/_blazor');
}
});
</script>
Sample code
Sample code for this project is available on GitHub .
Want to know more about our course? Here you go .