Introduction

C'mon, we all know we're here to push forward component-based architecture. Modern frameworks like React and Blazor do this effortlessly. But HOW do they do it?

At least I know the secret for Blazor, and I’m pretty sure I’m 95% right on this one. It all comes down to interactivity. Let me take you behind the scenes. We'll explore how SignalR and Render Trees drive the whole process.

If you’re new to Blazor, I’ve previously covered the basics of Blazor as a Single Page Application (SPA) and its server-side rendering in my article What makes Blazor SPA and how does Server-Side Rendering work with Blazor's new Web App.

The architecture

I've scribbled something down, and while I'm pretty sure this is how it's supposed to work, am I 100% certain? What am I, know it all?

Architecture

Image 1. The architecture of Blazor Server Interactivity

This architecture is broken down into what I like to call the 12 Steps of Interactivity.

  1. Initial Request: The user initiates a request to load the Blazor app in the browser.
  2. Response and Setup: The server responds with the initial HTML, CSS, and blazor.web.js, rendering the DOM in the browser.
  3. SignalR Connection: blazor.web.js establishes a WebSocket connection with the server using SignalR.
  4. In-Memory Representation: The server creates an in-memory render tree representing the initial state of the webpage.
  5. User Interaction: The user interacts with the page (e.g., clicks a button or inputs text).
  6. Capture Interaction: blazor.web.js captures the interaction and sends it as a binary message through SignalR to the server.
  7. Render Tree Update: The server processes the interaction and updates the in-memory representation, creating a new render tree.
  8. Diffing Process: The server compares the "new render tree" with the "old render tree" to identify the differences.
  9. Patch Creation: Differences between the old and new render trees are packaged into a binary message.
  10. DOM Update: The server sends this binary message back to the client through SignalR.
  11. DOM Patching: blazor.web.js applies the changes to the existing DOM, updating only the modified parts.
  12. User Sees Changes: The user experiences updated UI elements without a full-page refresh, and the user is happy with the interactivity and quick responsiveness of the application.

The explanation

In a traditional web application, the browser handles user interactions by sending requests to the server, which then processes these requests and sends back updated HTML. Blazor Server, however, uses a different approach.

The Role of blazor.web.js

Blazor Server interactivity starts with a special JavaScript file called "blazor.web.js". This file is responsible for setting up a real-time communication channel between the browser and the server.

Establishing the SignalR Channel

When you first load a Blazor Server app, the browser sends an initial HTTP request to the server, which responds with the HTML needed to render the page. This also includes the blazor.web.js file. Here’s what happens next,

At the Heart of Blazor Server, lie Render Trees

To efficiently manage updates, Blazor Server uses a concept known as render trees. A render tree is a lightweight, abstract representation of the DOM that represents the layout and state of your component. Blazor uses this to keep track of changes.

Old Tree vs. New Tree

Diffing Process

Patching the DOM

How Does SignalR Help?

In traditional web apps, each user interaction requires a round-trip to the server, resulting in new objects being created and disposed of for every request. Blazor Server, however, keeps everything in memory and uses SignalR to maintain a persistent connection.

It is called Render-Free Differences, as Blazor only sends the differences between the old tree and the new tree, avoiding unnecessary re-renders.

Visualizing the Process in Action

Start your Blazor Server app and open it in your browser. Visit any page you like; here, I have the "Counter" page open.

Inspect the SignalR Connection

Use the Developer Tools (Ctrl + Shift + I) and navigate to the "Network tab". What you're seeing here is the full page load. This is your initial request, "Step 1" from the architecture.

Developer Tools

Image 2. Initial Request to Counter Page

Filter by WS (WebSocket) to see the SignalR connection.

You'll notice there are three entries. The highlighted one that says (_blazor?id) is the one we're interested in, it includes the "blazor.web.js" file that I keep talking about.

SignalR connection

Image 3. SignalR Socket

Monitor Messages

Click on the WebSocket connection (_blazor?id) to view the real-time messages exchanged between the server and browser. These messages are the binary representations of render tree changes.

Monitor Messages

Image 4. Diff Patches in the Form of Binary Messages

Observe Message Flow

In the following GIF, you can see how messages arrive in small portions of bytes each time I click the Count button. These messages send the updated DOM back to the browser.

Observe Message

GIF 1. Diff Messages Sent from Server to Browser on Each User Interaction

Conclusion

Blazor Server’s interactivity model really shakes things up for web development in .NET. It enables real-time, responsive web applications to work without the need for complex JavaScript frameworks. I hope you now understand how SignalR and the render tree diffing mechanism work together to ensure that only the necessary parts of the UI are updated. Understanding how blazor.web.js and SignalR work behind the scenes will give you a deeper appreciation for designing component-based web apps.

I’m honored to have recently become a Microsoft MVP (Contribution ID:b5021ca6-c3e6-4e38-bf50-8a4e1520ebc1), and I’d like to thank C# Corner and Microsoft for their support in this journey.

And as always, I'll see you in the next one.