Blazor has been on a journey and in order to understand Blazor's current state one has to look at its evolution starting from the beginning. Launched in 2018, Blazor initially started as an experimental project, aiming to leverage WebAssembly to run C# directly in the browser, allowing developers to build SPAs using .NET. This idea was realized with Blazor WebAssembly, which allowed the .NET runtime to execute on the client.
Blazor WebAssembly, commonly abbreviated as Blazor WASM, offers the most SPA-like experience among all Blazor options. When a user first visits a Blazor WASM application, the browser downloads the .NET runtime along with the application's assemblies (lots of .dlls) and any other required content onto the user's browser. The downloaded runtime is a WebAssembly-based .NET runtime (essentially a .NET interpreter) which is executed inside the browser's WebAssembly engine. This runtime is responsible for executing the compiled C# code entirely in the browser.
While Blazor WASM has received plenty of initial praise and has been improved over time, it's also been met with key criticisms which often revolve around the following areas:
Initial load time:
The requirement to download the .NET runtime and application assemblies upon the first visit can result in a significant initial load time. This is even more evident in complex apps with large dependencies and especially over slow networks.
While WebAssembly is widely supported in modern browsers there may still be issues with older browsers or certain mobile devices which can limit the reach of a Blazor WASM application.
Beside the usual SEO challenges which all SPA frameworks come with, the additional longer load times and slower performance of Blazor WASM can negatively impact SEO rankings.
To counter act some of these critiques, Blazor Server was introduced a year after Blazor WebAssembly, enabling server-side C# code to handle UI updates over a SignalR connection. Unlike in Blazor WASM, the client-side UI is maintained by the server in a .NET Core application. After the initial request, a WebSocket connection is established between the client and the server using ASP.NET Core and SignalR.
When a user interacts with the UI, the event is sent over the SignalR connection to the server. The server processes the event and any UI updates are rendered on the server. The server then calculates the diff between the current and the new UI and sends it back to the client over the persistent SignalR connection. This process keeps the client and server UIs in sync. Since the UI logic runs on the server, the actual rendering logic as well as the .NET runtime doesn't need to be downloaded to the client, resulting in a much smaller download footprint, directly addressing one of the major criticisms of Blazor WASM.
However, while innovative in its approach, Blazor Server has several downsides of its own which need to be considered:
Since every UI interaction is processed on the server and requires a round trip over the network, any latency can significantly affect the responsiveness of a Blazor Server app. This can be particularly problematic for users with poor network connections or those geographically distant from the server.
Each client connection with a Blazor Server app maintains an active SignalR connection (mostly via WebSockets) to the server. This can lead to scalability issues, as the server must manage and maintain state for potentially thousands of connections simultaneously.
Server resource usage:
Blazor Server apps are much more resource-intensive because the server maintains the state of the UI. This can lead to higher memory and CPU usage, especially as the number of connected clients increases.
Reliance on SignalR:
The entire operation of a Blazor Server app depends on the reliability of the SignalR connection. If the connection is disrupted, the app can't function. This reliance requires a robust infrastructure and potentially increases the complexity of deployment, especially in corporate environments with strict security requirements that may restrict WebSocket usage.
No offline support:
Unlike Blazor WebAssembly apps, Blazor Server requires a constant connection to the server. If the client's connection drops, the app stops working, and the current state can be lost. This makes Blazor Server unsuitable for environments where offline functionality is required.
ASP.NET Core Server requirement:
Blazor Static SSR
Despite Blazor's versatility, both the WASM and Server rendering modes suffer from serious drawbacks which make Blazor a difficult choice over traditional SPA frameworks, which by comparison don't share any of Blazor's problems and are architecturally simpler too.
Being aware of these challenges, Microsoft tackled some of the primary concerns of Blazor WASM and Server by rolling out Blazor Static SSR:
Blazor Static SSR, as shown in the diagram above, is a third rendering option which operates entirely independent of WASM or SignalR, instead leveraging an open HTTP connection to stream UI updates to the client. This approach, known as static site rendering, involves generating web pages server-side and transmitting the fully composed HTML to the client, where it then gets wired back into the DOM to function as a dynamic application.
During an initial page load, Blazor Static SSR behaves similarly to a traditional server-side application by delivering a complete HTML page to the user's browser. Additionally, it fetches a
blazor.server.js script that establishes a long lived HTTP connection to an ASP.NET Core server. This connection is used to stream UI updates to the client. This architecture is more straightforward, much like a classic server-rendered website, yet it provides a dynamic, SPA-like experience by selectively updating portions of the DOM and therefore eliminating the need for full page reloads.
The benefits over Blazor WASM and Blazor Server are twofold:
Reduced load times:
There's no need for users to download the full .NET runtime and application files when visiting the website, and as they navigate through the site, complete page reloads are avoided.
No SignalR connection is required which greatly reduces the load on the server and removes many of the complexities around WebSocket connections.
Nonetheless, Blazor Static SSR is not an actual SPA framework in the traditional sense. It doesn't allow for rich interactivity beyond web forms and simple navigation. It also doesn't allow for real-time updates as there is no code running on the client after the initial page was loaded:
To combat this, Blazor starting with .NET 8 enables the mixing of different modes and introduces a fourth rendering option called Auto mode.
In order to add interactivity to a Blazor Static SSR website one has to go back to creating either Blazor WASM or Blazor Server components. The auto rendering option aims to counter the main issues of Blazor WASM's slow load times and Blazor Server's requirement for a SignalR connection by using both rendering modes at different times:
A Blazor component operating in Auto-mode starts off by establishing a SignalR connection to enable immediate interactivity and bypass extended load times. Concurrently, it discreetly fetches the .NET runtime and all necessary dependencies to function as a Blazor WASM application. For later visits, Blazor transitions from the Server to the WASM version, maintaining SPA responsiveness without further dependence on the SignalR connection.
It's a fascinating approach which undoubtedly doesn't lack creativity or ambition. Even so, Blazor Static SSR incorporated with interactive components poses some old and new challenges too:
No interactivity without WASM or SignalR:
The biggest drawback of Blazor Static SSR is that it still relies on Blazor WASM or SignalR to become an interactive framework, which means it inherits not just one, but all of the many unresolved downsides when running in Auto-mode.
Combining three different rendering modes adds a lot of complexity on the server and presents a steep learning curve for developers who must comprehend and manage those complexities effectively.
No serverless deployments:
Deployments from a CDN are still not possible due to the reliance on ASP.NET Core.
No offline support:
Blazor Static SSR minimises full page reloads but still requires an active connection to stream updates to the UI.
While static content is easily cacheable, dynamic content that changes frequently can be challenging to cache effectively, potentially missing out on valuable performance optimisations.
Having said that, Blazor Static SSR also comes with a few benefits when it's not mixed with WASM or Server together:
Since SSR applications pre-load all the content on the server and send it to the client as HTML, they are inherently SEO-friendly. This allows search engines to crawl and index the content more efficiently.
Fast initial load:
Stability across browsers:
Overall Blazor is a remarkable achievement with buckets of originality and technical finesse, however with the exception of Blazor WASM, Blazor Server and Blazor Static SSR behave quite differently to traditional SPAs.
While Blazor Server is technically intriguing, offering a unique approach to web development, it paradoxically combines the limitations of both, a Single-Page Application and a server-intensive architecture, at the same time. To some extent Blazor Server represents a "worst of both worlds" scenario. Personally it's my least favourite option and I can't see any future in this design.
Blazor Static SSR deviates the most from the paradigm of a SPA. Apart from being placed under the Blazor brand it diverges significantly from the framework's initial architecture. Ironically this is where its strengths lie as well. Given that SPAs are inherently accompanied by their own set of challenges, the necessity for a SPA must be well-justified, or otherwise opting for a server-rendered application can be a more straightforward and preferable solution most of the times.
In my view, Blazor Static SSR is a compelling option that deserves to be its own framework, enabling .NET developers to enrich the functionality of everyday ASP.NET Core.
A word of caution
Would I opt for Blazor today? To be candid, probably not. While I maintain a hopeful stance on Blazor, I must remain truthful to myself. I've never been the person who blindly champions every Microsoft technology without critical thought. The truth is, currently Blazor is evolving into an unwieldy beast. In spite of its four rendering modes, intricate layers of complexity, and clever technical fixes, it still falls short when compared to established SPAs. This situation leads me to question the longevity of Microsoft's commitment and how long Blazor will be around. The parallels with Silverlight are hard to ignore, and without the .NET team delivering a technically sound framework, I find it hard to envision widespread adoption beyond a comparatively small group of dedicated C# enthusiasts who will accept any insanity over the thought of using JS.
An untapped opportunity?
Blazor not only in name but in glory too.
In fact, I'm quite surprised that we haven't seen such a development yet, but perhaps it's a matter of perspective. Maybe it has been a case of the wrong team looking at the wrong problem all along? After all the ASP.NET Core team excels in web development and not compiler design. Not every problem needs to be solved using SignalR or streaming APIs. Perhaps it's time to put a hold on more rendering modes and looking at Blazor through a different lens?
In my view, without doubt, this is the best path forward and I shall remain hopeful until then.