One Blazor in three flavors
The framework currently offers three different execution and hosting models:
First, there is Blazor Server, which relies on a stateful server to run the application. In this case, the rendering of Razor templates to HTML takes place on the server. Via a SignalR connection, user interactions are reported from the web browser to the web server, triggering a re-render there. The server returns a diff of the changed HTML content over the same connection (see Figure 1). Any .NET code can be executed on the server, and all platform-specific interfaces can be used. In addition, the code on the server is protected from third-party inspection.
In contrast, Blazor WebAssembly allows the application to run completely on the client as a Single-Page Application (SPA). When the application is invoked, all required source files are loaded from the web server. This can be a static web server, with no special requirements. At runtime, HTTPS and WebSockets connections (e.g. via SignalR) are used to exchange data with APIs (see Figure 2).
Finally, there’s a third variety: Blazor Hybrid. Here, the web-based user interface is embedded via WebView in a .NET Multi-platform App UI (MAUI), WPF or Windows Forms application. Rendering is done by the application itself, WebAssembly is not used at all. The source files are delivered as a part of the application package, so the application can be run offline. In addition, as with Blazor Server, all platform-specific interfaces can be accessed.
Blazor WebAssembly is the tool of choice in many cases
In this article, we will mainly focus on Blazor WebAssembly, which seems to be more suitable for many types of web applications: This is because Blazor Server requires the operation of a server as well as a permanent and stable connection with low latency to it. Delays are already noticeable to the user in the range of a few dozen milliseconds. If the connection is lost altogether, the application can no longer be operated at all, as Figure 3 shows. Since the server is stateful, it can only serve a certain number of users simultaneously. This can be a problem for scaling.
Offline scenarios also cannot be reasonably implemented with Blazor Server, as would be desirable for Progressive Web Apps (PWA). With Blazor Hybrid, on the other hand, only desktop or mobile applications can be built, which requires deployments via the usual platform-specific paths such as installers or app stores—these applications cannot be run in the browser. Conversely, however, apps written in Blazor WebAssembly that run in the browser could also be packaged for desktop and mobile platforms, such as via Electron or MAUI. An overview of the above points is provided by Table 1.
Calling arbitrary platform-specific interfaces
(only if packaged)
(only on server)
Support for offline capability
Executable in browsers
Packageable for mobile/desktop plattorms
Code can be kept secret
Table 1: Overview of the functional features of the individual hosting models
In the projects we have been involved with at Thinktecture, Blazor WebAssembly has predominantly proved to be the more suitable choice. Only in one project where a machine control system was involved Blazor Server was chosen since it is not possible to communicate directly with the unit from the web browser, and the control PC is located directly next to the machine, which is why offline scenarios are not relevant. The approach is also suitable if the binary code is not to be transferred to the user’s computer for confidentiality reasons.
Does it have to be Blazor?
The choice of a suitable technology is often made at the very beginning of a project. This depends, among other things, on the experience and development potential of the team of developers. Angular uses many concepts known from the Extensible Application Markup Language (XAML) and of the Windows Presentation Foundation (WPF). The TypeScript programming language used in Angular was designed by Anders Hejlsberg, the same language designer responsible for C#. For these reasons, Angular is also a reasonable choice for a team of .NET developers.
Blazor is not a magical Windows-to-web converter
Similarly, SPAs written with Blazor WebAssembly must integrate with the same authentication flows as other web applications. Currently, authentication in Blazor is based on the outdated oidc-client.js library, a planned rebuild for .NET 7 unfortunately did not make it into the release.
Blazor also uses the Component-Based Software Engineering (CBSE) approach: An application is broken down into many small, reusable components. The framework has also recently been further developed in this respect, for example, since .NET 5 it has been possible to isolate CSS styles per component, a feature that has been available since the first release of Angular.
Furthermore, the framework runs in the browser, so developers need to be able to understand error messages and debug there as well. Blazor WebAssembly is therefore not a miraculous machine that simply converts .NET apps to the web. It is the same abstraction layer that Angular, React, or Vue represent—including all advantages and disadvantages.
Developers should also use Windows systems. Even though Blazor apps can be implemented with JetBrains Rider or on Visual Studio for Mac, and the support has undergone several improvements, development including debugging only works really well in Visual Studio 2022 on Windows. For example, Hot Reload, the immediate reloading of the application after changes in the source code, only works in this development environment. Rider did not have full support for the new SDK immediately after the release of .NET 7.
Mobile users and firewalls can cause problems
Another decisive factor for the choice of technology is the target group of the application: Is it a publicly accessible application or an internally used tool? The reason for this is the bundle size of Blazor WebAssembly applications. Even a simple Hello World application with Blazor WebAssembly is already 5.7 megabytes large (see Figure 4), while a comparable Angular application starts at about 150 kilobytes. The basis for comparison here are the Hello World applications that are created via dotnet new blazorwasm-empty or ng new. The transferred bytes of the uncompressed productive builds that can be built with ng build or dotnet publish -c release are counted. The used versions were the .NET SDK 7.0.100 and Angular 15.0.0. With activated Brotli compression, the size of Angular can be reduced to about 50 kilobytes, if you additionally switch off culture information in Blazor WebAssembly, you can reach a bundle size of 2 megabytes. Blazor also caches the DLL files, so they don’t have to be downloaded again the next time they are requested. While there have been significant improvements recently, Blazor’s size overhead will never go away entirely: Since .NET isn’t web-based, appropriate translation layers must be included. If the application is also to be used on mobile, the sheer scale of Blazor apps can already be the dealbreaker. The initial runtime performance of Blazor apps is also not ideal: after Blazor boots up, the .NET assemblies are downloaded, thus resulting in a long loading time for the user, during which all they see is a loading screen.
In one project, the firewall deployed at an end customer prevented the .NET assembly DLL files from being downloaded, rendering the Blazor app completely useless. It is understandable that security solutions consider downloading a large number of DLL files as a threat. Unfortunately, AoT compilation does not remedy this, but actually makes the size situation even worse, as the resulting WebAssembly bundles sometimes become twice as large. In addition, the number of transferred DLLs is only reduced, since for Reflection, for example, .NET assemblies still have to be transferred. Whether this can be further optimized is questionable. In this respect, Blazor WebAssembly is rather unsuitable for B2C solutions where the environment such as firewalls or mobile use cannot be controlled. But even for B2B applications or entirely internal solutions, the size and runtime performance of applications can become problematic: One customer’s employee dialing into the corporate network from home via VPN had to wait about 20 seconds for a Blazor application to launch. Another customer switched from Blazor WebAssembly back to Angular in frustration due to the significantly worse runtime performance, since he had already used Angular before and Blazor offered no advantages.
Built-in solutions for better performance
The server-side prerendering of Blazor WebAssembly, which has been available since .NET 5, can provide a partial remedy here. The page is pre-rendered on the server side, and the finished HTML is transferred to the client (see Figure 5). This in turn requires the operation of a server configured for this purpose. Without prerendering, the source files of the application can be transferred to any static web server and executed from there. Furthermore, developers must additionally test this behavior.
Once loaded, however, a Blazor WebAssembly app can achieve roughly the same speed as any other web application—with the same pitfalls that apply to all other frameworks: Such as rendering too much data. An essential factor for runtime performance is the number of displayed nodes in the Document Object Model (DOM). A list with thousands of rows should not be rendered directly. Alternatives are paging or virtualized lists. For the latter, Blazor WebAssembly even offers a built-in solution, unlike Angular and co: The component optimizes the rendering of list data by only actually inserting the currently visible records into the DOM. The underlying data can either be kept in memory or dynamically reloaded as needed. This results in optimal runtime performance even for very long lists. Another option added with .NET 7 is the experimental QuickGrid, which also includes paging.
Blazor WebAssembly is primarily suited for internal enterprise applications where the environment can be clearly controlled, where there is existing .NET and C# expertise, where a move to other approaches is not feasible, and where Windows is used as the development environment.
Due to its unusual architecture and poor scalability, we recommend avoiding Blazor Server if possible and prefer Blazor WebAssembly instead. Only this flavor of the framework fits with other single-page app approaches like Angular, React, or Vue, supports offline capability, and can also be hosted in Electron or MAUI using the exact same source files.
In short, the Blazor WebAssembly concept for forms-over-data business applications works very well, it is sufficiently stable and mature. In addition, Microsoft is constantly developing the framework family further.