An introduction to Blazor
Today I’m not going to talk about how to develop a Blazor application. Instead, I’m trying to explain to you guys How a Blazor application is written in .NET/C# can run and render the UI in the browser? What are the differences between Blazor WebAssembly and Blazor Server?
As far as I knew since 1995, JavaScript is the only language that works directly with the DOM (Document Object Model). So, Can C# now do it as an alternative to JavaScript? How can .NET code run directly in the browser?
Note: To understand what I trying to explain here, I’m assume that you guys already have knowledge and experience working with SPA web applications and ASP.NET web development. I using Blazor WebAssembly App template and Blazor Server App template from visual studio 2019 and .NET 5 for demonstration.
Blazor WebAssembly
What is the WebAssembly? Based on this document, historically, JavaScript worked well for us and powerful enough to solve most problems people have on the Web today. However, We have run into performance problems when trying to use JavaScript for more intensive use cases like 3D games, Virtual and Augmented Reality, computer vision, image/video editing, and several other domains that demand native performance (see WebAssembly use cases for more ideas). WebAssembly was coming. It is a new type of code that can be run in modern web browsers and provides new features and significant gains in performance. It is not primarily intended to be written by hand; instead, it is designed to be an effective compilation target for source languages like C, C++, Rust, etc. It provides a way to run code written in multiple languages on the web at near-native speed, with client apps running on the web that previously couldn’t have done so.
What’s more, you don’t even have to know how to create WebAssembly code to take advantage of it. WebAssembly modules can be imported into a web (or Node.js) app, exposing WebAssembly functions for use via JavaScript. As a result, JavaScript frameworks could make use of WebAssembly to confer massive performance advantages and new features while still making functionality readily available to web developers. Let's look into this as an example of porting a C method to the wasm file and running it in the browser.
Please note that WebAssembly cannot currently directly access the DOM — at least it is for still now (July 2021). Instead, it can only call JavaScript, passing in integer and floating-point primitive data types. Thus, to access any browser Web API, WebAssembly needs to call out JavaScript, which then makes the browser Web API call. Emscripten, therefore, creates the HTML and JavaScript glue code required to achieve this.
In short, WebAssembly provides a way to run code written in multiple languages on the browser.
How? By using the compiler to compile the code to a wasm module. Then the browser will load, instantiate and run via JavaScript. An example here.
Back to Blazor WebAssembly, How does it works?
When you define a Blazor component, you are allowed to use HTML and C#. They are compiled to C# classes after we trigger the MSBuild under the hood. To represent the HTML part in C#, Microsoft introduced some kind of compilation. To show this more visually, see the example below:
Output: (You can find the outcome as below in /obj/Debug/{.NET version}/Razor)
You can see that the C# part is the same, but the HTML part is totally different. Each element that contains something with C# is represented by adding its multiple parts in the RenderTreeBuilder. So, a new term comes up, RenderTree. We can understand it is a virtual DOM — just like what we already know in Vue.js or React + an Incremental DOM approach. Incremental DOM is a technique that minimizes the amount of work needed to update the elements in a browser’s view. Creating a diff-tree gives us the ability to represent changes to the UI using the smallest number of changes possible to update the DOM — which saves time when changing the display (so the user experience is better).
What next? The Blazor WebAssembly application source code will compile to dotnet.wasm file and generate a JavaScript file (blazor.webassembly.js) as a glue code mentioned above. This JavaScript file is also responsible for bootstrap the whole process to host a mono runtime instance in the browser sandbox environment via the dotnet.wasm file.
So, now we can imagine at the runtime, a Blazor WebAssembly will work as below:
First, the browser makes a request to the server, which contains the artifact from the build process.
The server will respond to the client the index.html document — which defines a minimum of required static resources to bootstrap the process. Most important is the blazor.webassembly.js file.
After the browser downloads the blazor.webassembly.js successfully, it will automatically fetch the blazor.boot.json file, and based on that file, the wasm file and all .NET assembly files will also fetch to the browser.
Please notes that all files in the boot config download to the browser for the first time only. After that, it caches in the browser still the new content if the integrity has changed.
Then via the dotnet.wasm file, a WebAssembly instance is initialized on top of mono WebAssembly runtime. All dependency assemblies will load into the RAM. Finally, a mono web application is ready to serve.
I’m assuming that the web app is running in the browser already. So, I’ll select the Counter component — which is registered to /counter route, to demonstrate how that component renders and update the DOM.
The Program.cs file describes the starting point of a Blazor app.
What next? The App component will be created as a root component which will mount to the HTML element with id = app (see index.html above for more detail). After that, by matching with the routing table by /counter URL, the Counter component will be select and created as a child of the App component. So, eventually, it makes a RenderTree available in the memory as a virtual DOM.
And as I’ve mentioned above, the WebAssembly standard, in general, does not allow direct interaction with the DOM. Instead, all exchanges must flow through JavaScript interop. Therefore Blazor WebAssembly sent painting instructions commands back to the JavaScript side. JavaScript then converts these commands to browser Web API calls, which interact directly with the DOM and let the browser paint the UI itself.
In short, Blazor WebAssembly doesn't interact directly with the DOM, but via JavaScript interop instead.
What happened if you click on the button? Well, the same process will apply. Via JavaScript event handlers, your commands from the browser will pass to the WebAssembly to calculates and update the virtual DOM. Then the WebAssembly will command back to the browser to update the DOM via JavaScript interop.
Note: Don’t do DOM manipulation manually. It’s a bad practice to do it with a framework like this. Actually, you can manipulte the DOM with JavaScript interop, but there is no guarantee that your change won’t be erased because Blazor keeps the app’s state in memory.
Pros
- There’s no .NET server-side dependency. The app is fully functioning after it’s downloaded to the client.
- Client resources and capabilities are fully leveraged.
- Work is offloaded from the server to the client.
- An ASP.NET Core web server isn’t required to host the app. Serverless deployment scenarios are possible, such as serving the app from a Content Delivery Network (CDN).
Cons
- Sizeable initial download of the .NET framework to the browser on the first load. → The app takes longer to load.
- The app is restricted to the capabilities of the browser.
- Capable client hardware and software (for example, WebAssembly support) is required .NET runtime and tooling support are less mature. For example, limitations exist in .NET Standard support and debugging.
IMHO, for any line of business apps, the initial download is unlikely to pose a major issue. Furthermore, Blazor WebAssembly also offers a lazy load mechanism to cut down the initial download size or the config linker approach here.
Blazor Server
This document is a good starting point for Blazor Server awareness.
In terms of render and up UI, Blazor Server performs the same as Blazor WebAssembly does. Build RenderTree as a virtual DOM, and use Javascript interop to interact directly with the DOM. The main differences:
The Blazor Server hosting model, the app is executed on the server from within an ASP.NET Core app. So, The app takes full advantage of server capabilities.
On the client, the blazor.server.js
script establishes the SignalR connection with the server. The script is served to the client-side app from an embedded resource in the ASP.NET Core shared framework. The client-side app is responsible for persisting and restoring the app state as required.
UI updates, event handling, and JavaScript calls are handled over a SignalR connection.
The bootstrap HTML document is come from /Pages/_Host.cshtml instead of index.html
Let’s pay attention to the prerendering process of Blazor Server, which differs from traditional models for rendering UI in ASP.NET Core apps using Razor views or Razor Pages. First, the requested Razor component is compiled on the server into static HTML and sent to the client, where it’s rendered to the user. After the connection is made between the client and the server, the component’s static prerendered elements are replaced with interactive elements.
Pros
- Download size is significantly smaller than a Blazor WebAssembly app, and the app loads much faster.
- The app takes full advantage of server capabilities, including the use of any .NET Core compatible APIs.
- .NET Core on the server is used to run the app, so existing .NET tooling, such as debugging, works as expected.
- Thin clients are supported. For example, Blazor Server apps work with browsers that don’t support WebAssembly and on resource-constrained devices.
- The app’s .NET/C# code base, including the app’s component code, isn’t served to clients.
Cons
- Higher latency usually exists. Every user interaction involves a network hop. Latency may become noticeable to users, particularly if users are widely distributed geographically.
- There’s no offline support. If the client connection fails, the app stops working.
- Scalability is challenging for apps with many users. The server must manage multiple client connections and handle client states.
- An ASP.NET Core server is required to serve the app. Therefore, serverless deployment scenarios aren’t possible, such as serving the app from a Content Delivery Network (CDN).
A Blazor Server app prerenders in response to the first client request, which creates the UI state on the server. When the client attempts to create a SignalR connection, the client must reconnect to the same server. Blazor Server apps that use more than one backend server should implement sticky sessions for SignalR connections. So, go with the Azure SignalR Service is a good option if you want to go with Blazor Server hosting model.
Is Blazor faster than others JavaScript SPA like Vue.js, React in terms of DOM manipulation?
I’m not precisely doing a performance test between Blazor and others SPA libraries/frameworks. But IMHO, even the WebAssembly can load and run faster than JavaScript, but at runtime, in terms of render and update the web UI, that process has to go through an abstract/wrapper layer and then call the browser Web API to manipulate the DOM anyway. Furthermore, calls between .NET and JavaScript involve some additional overhead because of the JSON-serialized process. So, the Blazor mightn’t be faster than others in the daily use case. But the performance will significant improve if your app type is listed here.
Conclusion
Pros
- You can stick to the ecosystem you already know (NuGet, the .NET tooling, Visual Studio/VS Code). Furthermore, one syntax across your full-stack will improve the onboarding of inexperienced developers. That’s a HUGE selling point for Blazor. You don’t need multiple skills or a development environment for building a Web Application.
- So far, Blazor provides all the features you need for building a complete application: routing, templating, data binding, forms, network, authentication, authorization, libraries, etc., like with any SPA framework.
- Blazor provides the way that you can invoke JavaScript (JS) functions from .NET or invoke .NET methods from JavaScript (JS) directly.
- You can share models between client and server will significantly improve your productivity. For example, imagine this: you can share the data computation or validation rules for both client-side and server-side as below.
Cons
- Developers need .NET and Microsoft skills set to getting started with Blazor.
- Blazor is mostly its integration in the entire .NET ecosystem.
- List of Blazor Server’s bugs/issues.
- List of Blazor Client’s bugs/issues.
- Young community.
- Fewer resources available on the internet (tutorial, free shared components) than Vue.js/React.
Most of the time, decisions are made based on feelings, taste, and experience. However, if you are a web developer with experience working on the stack of .NET, especially in ASP.NET technologies already, and you want to build a SPA web app with that skill set, then Blazor is the best choice.
If your SPA app is a 3D game, image/video editing, and several other domains that demand native performance, Blazor WebAssembly is a potential candidate.
If your app serves a lot of concurrent users or high interaction requests from the UI in a short time, then be careful with Blazor Server because of the network latency and the limit on the scalability of this hosting model. It could negatively impact the UX of your application. It would help if you separated the responsibilities of the Blazor app as a presentation layer on the client side. The Blazor app will consume all application logic and domain logic through the web APIs then. By doing that, we are good to go with the Blazor WebAssembly hosting model to tackle the cons of the Blazor Server I’ve mentioned above.
Be aware and follow the performance best practices and the license cost for external components/libraries/toolsets if you go with some enterprise UI products as your dependency such as Telerik, Syncfusion, DevExpress. IMHO, an enterprise third-party UI framework can speed up the development time, but the trade-off is it might depend on their development roadmap, reduce the flexibility to customize UI on specific business demands, and add significant efforts to optimize the front-end’s performance.
Blazor is a revolution of modern SPA web application development using Microsoft technology. What do you think about Blazor? Is it cool? So, asking yourself is it appropriate for your project and give it a try.