Modal Title
Frontend Development / Software Development / WebAssembly

No More JavaScript: How Microsoft Blazor Uses WebAssembly

David Eastman explains how Microsoft has smoothed the path for WebAssembly. You'll be tempted to leave JavaScript behind after this.
Mar 27th, 2023 7:22am by
Featued image for: No More JavaScript: How Microsoft Blazor Uses WebAssembly

Last week I introduced you to Blazor, Microsoft’s web stack that eschews JavaScript and enables developers to use WebAssembly on the client side. We saw quite a pleasing HTML/code separation on templates and a solid component system.

Now it is time to venture further into the purple man’s domain (the presenter in the explainer videos, Jeff Fritz, wears a very fetching purple blazer) and beyond.

You will remember previously that you can have multiple routes marked out on the page. We can see an interesting variant using this on the example Counter.razor:


We can add another route to this one, which takes an argument that binds with StartingValue. You can see how readable this is:


This takes a parameter from the URL and puts it straight into the code (allowing for capitalization differences) using an override. Clearly, we are picking up an OnParameterSet event. Without the parameter present, the code works as before. If I do have a parameter that matches the type int, we get:

This sets us up for the trickier binding of different types of HTML UI elements to C# code.

But for now, we will leave the Purple Man’s video lessons for a more pressing issue. This is the bit where we want to talk about the (purple) elephant in the room.

Are We Just Creating Server-Side Apps?

The answer is no. It is Microsoft’s business to create a unified development environment and blur the line between server-side and client-side. But they do make it clear they are different projects:

However, there are a few shiny but confusing baubles in the explanations for the two options above. WebAssembly directly supports .NET on the browser, and thus gives you offline behavior. In the Server App, no C# goes to the client at all. SignalR sounds like a toothpaste, but it is just asynchronous communication helper code for the client/server connection.

You may also have noticed that the last sentence in both descriptions is identical. Microsoft is trying to square off its older systems with ways to support modern techniques while protecting its platform legacy.

Differences Between the Server and Wasm Apps

I want to compare the differences in approach between a server and a WebAssembly-based app by looking at an example component.

So what are the differences? The demo project I have been using is, under the hood, a Blazer Server. So let’s look at the simple FetchData example. It shows some fake weather:

On the backend is this a simple fake service in pure C#:


Note the use of Random to generate results, as you might expect. Each time I refresh, I get some different fake data.

Naturally, there is a FetchData.razor for the page, and it has two interesting parts:


The inject directive is a form of Dependency Injection; Blazor uses this so that components can use available services in an independent manner — a real service in the wild would not be part of the calling program.

Here is the corresponding code at the bottom of FetchData.razor:


We know the rest of the code on the page is just going to loop through the array of WeatherForecast and display it.

So we are just missing the code that “registers” this service. That is added to the boilerplate of Program.cs:


It appears that the design treats the pages themselves as separate services. All components requiring a singleton service receive the same instance of the service.

So in summary, we make a fake service for our server, register it, then “inject” it into the pages of the App. The client’s only responsibility is to display the information — and that is done in the rest of FetchData.razor by some simple HTML.

This cannot possibly be the model for a WebAssembly client. So let’s pull in the WebAssembly equivalent of the demo project and compare the differences. And yes, there is a FetchData example in this project too. It runs the same as the server version, except there is a few seconds to wait for .NET to load into the browser. The data doesn’t change after refresh (we will see why shortly). This wait is acceptable as long as the page will claim the user’s interest for some amount of time. We can imagine that this will improve over time, too.

Let’s start with the top of FetchData.razor:


Ah — so we are not injecting some backend fake service. Because, or course, there is no backend. In the demo, the method used is an HttpClient, so you can suck up some data in a nice REST service.

How will that be applied?


Ah, so the service is now an HTTP call for some trusty fake JSON.

The static JSON file is sitting in the wwwroot directory of the project, and hence the data won’t refresh when the app runs:


We still need to find out how we register this service, and also find out why the HTTP started looking in our wwwroot. The answers happen to be on the same line:


So we add the HttpClient service and, in this case, the base address is set to the Host Environment. A Scoped service is tied up with the lifetime of an HTTP connection.

While supporting subtle differences in approach, the two projects are largely the same. I hope this quick look at how Microsoft has smoothed the path for WebAssembly has tempted you to leave JavaScript behind and put on a colorful jacket.

Group Created with Sketch.
THE NEW STACK UPDATE A newsletter digest of the week’s most important stories & analyses.