Walkthrough: our migration from Blazor Server to Blazor WebAssembly
Audacia
Posted on July 15, 2022
Blazor Server and Blazor WebAssembly are two of the five flavours of Blazor that developers can use today.
There are many differences between these two types of Blazor. The main distinction for us revolved around the following:
For Blazor Server applications, the app is hosted and run on the server. The client therefore downloads a very small web application, with page updates being served via a SignalR connection.
Conversely, Blazor WebAssembly works as a single-page application which means that the application is run on the user's browser as opposed to the server. This means that data access would need to happen via communication with the server. For example, by means of a REST API.
You can find a full review of these differences on our dedicated review of Microsoft's Blazor Web Framework
Olympus
Olympus is an internal project for delivering a system that Audacia staff will use for a large part of their day-to-day activities. In 2019, we decided we wanted to replace our existing management system. At Audacia, we have always been keen to learn the latest technologies. At the time Blazor Server had just been released in 2018 as part of .NET core 3.
Being a Microsoft Gold Partner with years of experience in .NET development, we were very excited by the prospect of writing entire applications in C#. From here, we decided that Olympus would be written in Blazor.
Olympus uses an Azure SQL database for data access via Entity Framework Core and has a command-pattern style architecture for performing business actions. We use Azure AD for authentication, which means that any new starters will be able to log in with their Microsoft account from day one.
Blazor WebAssembly was released in May 2020. With Microsoft stopping support of .NET Core 3.1 in December 2022, we had already been proactive with upgrading Olympus to be on .NET 6. This had the added benefit that we could move our application to use Blazor WebAssembly.
The work to implement this change was broken down as follows:
- Build & Deploy an ASP.NET Core API, authenticated with Azure AD.
- Update the front end to make HTTP requests for the new API, rather than access the DbContext directly.
- Migrate the front end to a Blazor WebAssembly application, so that it's loaded in the user's browser. ## Why?
Familiarity
At Audacia, we specialise in web applications of the fairly well-known three-tier architecture:
- SPA front end (e.g Vue, React, Angular)
- REST API (usually .NET)
- Data Access via Entity Framework Core (e.g SQL Server, MongoDB)
Blazor WebAssembly applications can be thought of as alternatives to other well-known frameworks for SPAs. The process of moving Olympus to this hosting model would mean that development teams would already be familiar with 2/3rds of the architecture.
API Test Automation
An increasing number of projects at Audacia have automated tests setup for their APIs. Blazor Server applications don't accommodate this as there's no exposed API.
Having a dedicated API for the application would give us the extra security and reliability that API test automation gives us. You can find out about our approach to API testing automation in our blog post Automated Testing of APIs .
Performance Testing
In a similar vein, dedicated APIs allow us to use JMeter to run performance (or load) tests against the application. We cover all things performance testing in this blog post.
WebAssembly
WebAssembly was first released in 2018 and is a new way of developing web applications. This technology allows us to create entire applications without writing a line of javascript. The adoption of this technology is growing rapidly.
Though some might say Microsoft was late to web, it certainly wasn't for WebAssembly. This blog post goes into great detail on how WebAssembly works and why it's so popular.
How?
Step 1 - API
Building and Deploying an ASP.NET Core API as an Azure App Service was very much in our comfort zone. Once we had a simple 'Hello World' API written, our app services for the production environment looked like the following:
olympus-production
continued as the front end of the application, which means that we had two deployed websites: one front end that would eventually be a Blazor WebAssembly application, and our new REST API.
Achieving Authentication via Azure AD was the next milestone, and we had to set up extra App Registrations in order to have an authenticated API.
As the front end had no knowledge of the API at the time, we decided to implement swagger. This action would prove that we could authenticate a standalone HTTP request with Azure AD.
There are lots of resources online to help set up Azure AD Authentication for an API. Once we did this, we added a test endpoint to prove that it would return a 401 when not authorised.
Then we could prove authorisation was working correctly once authorised through swagger:
Step 2 - Make HTTP requests
The next step was to access data via the new API, rather than call our services directly. This involved adding a step inbetween the UI and the service it called.
Implementing this required writing new endpoints for each business action and updating the UI to call endpoints rather than services directly.
All application logic in Olympus is called using an ITask
interface:
namespace Audacia.Olympus.Ui.Tasks;
public interface ITask
{
Task PerformAsync(CancellationToken cancellationToken = default);
}
Therefore, having something that made a HTTP request in the PerformAsync method would achieve what we wanted:
using Audacia.Olympus.Ui.Constants;
namespace Audacia.Olympus.Ui.Tasks;
public class OlympusApiTask : ITask
{
private readonly HttpClient _client;
private readonly HttpRequestMessage _message;
public OlympusApiTask(IHttpClientFactory clientFactory, HttpRequestMessage message)
{
_message = message;
_client = clientFactory.CreateClient(HttpClients.OlympusAPI);
}
public async Task PerformAsync(CancellationToken cancellationToken = default)
{
var result = await _client.SendAsync(_message, cancellationToken);
result.EnsureSuccessStatusCode();
}
}
Step 3 - Convert UI to Blazor WebAssembly
At this point, all business actions were implemented via HTTP requests. Olympus was, therefore, ready for Blazor to live on the browser.
- We updated the
.csproj
to reference the WebAssembly SDKs: Code sample showing the .csproj being updated to to reference the WebAssembly SDKs:
- Now it's building as a WebAssembly project, we updated our
Program.cs
to use the required WebAssemblyconfigurations:
We then set the project up with MSAL authentication by installing the WebAssembly-specific nuget package Microsoft.Authentication.WebAssembly.Msal
.
Crucially, we tell the entry point of the application (index.html) to load the WebAssembly scripts:
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
Wrap up
Getting this done proved to be a very difficult process, with its share of challenges along the way. For more detailed steps, this walkthrough is very useful.
Conclusion
This article has covered why we migrated our internal project to Blazor WebAssembly from Blazor Server. We have also outlined the steps taken to implement. We are excited by the benefits that this migration offers. In addition, we hope that this migration will prove that Blazor is viable for use in future projects.
This article was originally written for Audacia’s technical blog by Principal Consultant, Owen Lacey.
Posted on July 15, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.