Blazor Server vs. Blazor WebAssembly: Four ways in which they differ

Published: Monday 30 November 2020

Blazor Server and Blazor WebAssembly (also known as Blazor Wasm) differ in many ways. We look at four ways on how the Blazor hosting models are different.

Blazor is Microsoft's newest web framework. With it's enhancement for performance in .NET 5, it's expected to be a popular choice for building web applications.

That is because we can code client-side functionality using C#. No more need for JavaScript.

That alone is a good enough reason to use Blazor.

However, deciding on which Blazor hosting model to use is crucial depending on the type of application we are creating.

For example, if we wish to build a client-facing application that we wish to rank in Google, Blazor Server would be preferred. Whereas, if we wish for our application to work offline, Blazor WebAssembly makes that possible.

How The Different Blazor Hosting Models Work

It's good to have an understanding on how the different Blazor Hosting models work before looking at the differences.

Blazor Server

Blazor Server uses a standard ASP.NET Core application. Within that application, we can integrate server-side functionality, such as integrating a SQL Server database through Entity Framework.

In-addition, we can create client-side pages using Razor components or Razor pages.

When the application is running, the browser sets up a constant connection with the Blazor Server application using SignalR. This is how the browser communicates with the Blazor Server application.

How Blazor Server Works Between Client and Server

How Blazor Server Works Between Client and Server

Blazor WebAssembly

Blazor WebAssembly uses WebAssembly. WebAssembly is supported in most modern day browsers. But, it's not supported in IE11.

The way it works is that it allows the browser to download the Blazor application.

This means that the Blazor application runs in the web browser. No need for a constant connection with a server for the application to work.

However, because it's solely a client-side application, we can't directly integrate any server-side functionality into the Blazor application.

In-order to do that, we would need to hook it up with a server-side application, such as an ASP.NET Core Web API.

Like with Blazor Server, we can create client-side pages using Razor components or Razor pages.

How Blazor WebAssembly Works in the Browser

How Blazor WebAssembly Works in the Browser

How The Blazor Hosting Models Differ

Now that we have an understanding on how each Blazor hosting model works, that's have a look on how they differ.

#1: Initialisation

For both examples, we are going to use the default "WeatherForecast" application that comes with Blazor to show exactly how they work.

Homepage of Weather Forecast Demo for Blazor Server

Homepage of Weather Forecast Demo for Blazor Server

We are going to use Google Developer Tools and map the timeline of the homepage.

From there, we will click on the Counter link and see how it differs.

Blazor Server

Google Developer Tools Network Timeline on Blazor Server Startup

Google Developer Tools Network Timeline on Blazor Server Startup

Looking above, Blazor Server loads in the HTML, and CSS. It also loads in a Javascript file (blazor.server.js), which initialises a connection to SignalR via websockets.

It loads 9 requests and has finished loading them in 317 milliseconds.

Now that's click on the Counter link and see how it affects the timeline.

Google Developer Tools Network Timeline on Blazor Server Link Click

Google Developer Tools Network Timeline on Blazor Server Link Click

There is no new network activity when clicking on a link in a Blazor Server application.

That is because the data is being sent through our active SignalR connection.

So the Counter page is requested through the link click which sends it to the server. The server then returns the HTML for the Counter page. All this happens through SignalR.

Blazor WebAssembly

Google Developer Tools Network Timeline on Blazor WebAssembly Startup

Google Developer Tools Network Timeline on Blazor WebAssembly Startup

When we load a Blazor WebAssembly application, it has to download all the application into the browser.

For the demo Blazor application, it has to load in 203 requests at a load time of 4.13 seconds.

Bear in mind that the bigger our application is, the more resources will be needed to downloaded to the browser. The more resource, the longer load time.

Now, that's see what happens when we click on the Counter page.

Google Developer Tools Network Timeline on Blazor WebAssembly Link Click

Google Developer Tools Network Timeline on Blazor WebAssembly Link Click

It has loaded in the favicon.ico icon for some reason, but that's it.

It's largely the same as Blazor Server.

Or is it? Well the answer is no. That's because unlike Blazor Server, Blazor WebAssembly does not have to interact with the server. The application has already been downloaded into the browser.

That means that link clicks in the application are almost certainly going to load much quicker in Blazor WebAssembly than Blazor Server.

#2: Search Engines

When developing our Blazor application, we need to consider whether search engines will need to crawl our application.

Now, I'm no SEO expert, but it used to be that search engines struggled to render client-side functionality, such as JavaScript.

In recent years, there has been better support for JavaScript, but we are not dealing with JavaScript here. We are dealing with WebAssembly.

To avoid unnecessary risks, we have to assume that WebAssembly can't be rendered with search engines.

In that case, that's see how Blazor Server and Blazor WebAssembly support search engines.

To do this, we are going to run both applications, and the view the source code to see what gets generated.

Blazor Server

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>BlazorServer</title>
	<base href="/" />
	<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
	<link href="css/site.css" rel="stylesheet" />
	<link href="BlazorServer.styles.css" rel="stylesheet" />
</head>
<body>
	<!--Blazor:{"sequence":0,"type":"server","prerenderId":"4ac92f770c5545768b8a5dc2d1dbb1ba","descriptor":"CfDJ8CKP9bhtA1FDra8KT5Yqx3XxnJlhqWvM4D7YFhj9kd7ufZDfs8pArwZzSXs2mODlzP8LwITtsTx2CIwThTJoB1Wp\u002Bl6h\u002BacJst/P2rYRg2PKXX4PSf2eyqYLpM9kBW06hVCEk6l1g9z9Kl6Q6DD77DsG\u002BYKATlmXCDDJYJusRZF2A6ZvVnXuKRtMauUWb63wOEJNpuhQ2P4HldUpwrOOxJ\u002BFlR\u002BaWNdYY4L2r5CIUQResLp//lhbKIoVUm8ykICeYvZhl814IeTXPS1D54IYpA9Ynps12NrnzY2L5GrhcArrVtck2Bp6e/HDiTpTM8J9O/Sf6ONLQzfyGfZsQTUNDn5zlASdnqlokqDsigdlzSG6"}--><div class="page" b-mxoy4q7bj7><div class="sidebar" b-mxoy4q7bj7><div class="top-row pl-4 navbar navbar-dark" b-9s0xq2xzhp><a class="navbar-brand" href b-9s0xq2xzhp>BlazorServer</a>
	<button class="navbar-toggler" b-9s0xq2xzhp><span class="navbar-toggler-icon" b-9s0xq2xzhp></span></button></div>
 
<div class="collapse" b-9s0xq2xzhp><ul class="nav flex-column" b-9s0xq2xzhp><li class="nav-item px-3" b-9s0xq2xzhp><a href="" class="nav-link active"><span class="oi oi-home" aria-hidden="true" b-9s0xq2xzhp></span> Home
            </a></li>
		<li class="nav-item px-3" b-9s0xq2xzhp><a href="counter" class="nav-link"><span class="oi oi-plus" aria-hidden="true" b-9s0xq2xzhp></span> Counter
			</a></li>
		<li class="nav-item px-3" b-9s0xq2xzhp><a href="fetchdata" class="nav-link"><span class="oi oi-list-rich" aria-hidden="true" b-9s0xq2xzhp></span> Fetch data
			</a></li></ul></div></div>
 
	<div class="main" b-mxoy4q7bj7><div class="top-row px-4" b-mxoy4q7bj7><a href="https://docs.microsoft.com/aspnet/" target="_blank" b-mxoy4q7bj7>About</a></div>
 
	<div class="content px-4" b-mxoy4q7bj7><h1>Hello, world!</h1>
 
Welcome to your new app.
 
<div class="alert alert-secondary mt-4" role="alert"><span class="oi oi-pencil mr-2" aria-hidden="true"></span>
	<strong>How is Blazor working for you?</strong>
 
	<span class="text-nowrap">
		Please take our
		<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2137813">brief survey</a></span>
	and tell us what you think.
</div></div></div></div><!--Blazor:{"prerenderId":"4ac92f770c5545768b8a5dc2d1dbb1ba"}-->
 
	<div id="blazor-error-ui">
         
         
		An unhandled exception has occurred. See browser dev tools for details.
         
		<a href="" class="reload">Reload</a>
		<a class="dismiss">?</a>
	</div>
 
	<script src="_framework/blazor.server.js"></script>
</body>
</html>

As we can see, a Blazor Server application outputs all the HTML into the source code.

Inside the source code, we can see the code for the links on the left-hand side of the page.

In addition, it has the content of the page which states "Hello, world!", "Welcome to your new app.".

This is great for search engines as it can read the content of our page without having to execute any client-side technology.

Blazor WebAssembly

<!DOCTYPE html>
<html>
 
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
	<title>BlazorWasm</title>
	<base href="/" />
	<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
	<link href="css/app.css" rel="stylesheet" />
	<link href="BlazorWasm.styles.css" rel="stylesheet" />
</head>
 
<body>
	<div id="app">Loading...</div>

	<div id="blazor-error-ui">
		An unhandled error has occurred.
		<a href="" class="reload">Reload</a>
		<a class="dismiss">?</a>
	</div>
	<script src="_framework/blazor.webassembly.js"></script>
</body>
 
</html>

Quite a difference with Blazor WebAssembly! It only loads the template into the source code.

The rendering of our application (in the "app" div element) is done through WebAssembly.

This is absolutely fine if we don't need to appear in Google's search results.

However, if it is, don't expect to appear on page 1 in Google's search results anytime soon.

#3: Server-Side Functionality

If we take a look at the Program and Startup class for a Blazor Server application, it looks similar to a ASP.NET Core Web API application.

// Program.cs
public class Program
{
	public static void Main(string[] args)
	{
		CreateHostBuilder(args).Build().Run();
	}

	public static IHostBuilder CreateHostBuilder(string[] args) =>
		Host.CreateDefaultBuilder(args)
			.ConfigureWebHostDefaults(webBuilder =>
			{
				webBuilder.UseStartup<Startup>();
			});
}
// Startup.cs
public class Startup
{
	public Startup(IConfiguration configuration)
	{
		Configuration = configuration;
	}

	public IConfiguration Configuration { get; }

	// This method gets called by the runtime. Use this method to add services to the container.
	// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
	public void ConfigureServices(IServiceCollection services)
	{
		services.AddRazorPages();
		services.AddServerSideBlazor();
		services.AddSingleton<WeatherForecastService>();
	}

	// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
	public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
	{
		if (env.IsDevelopment())
		{
			app.UseDeveloperExceptionPage();
		}
		else
		{
			app.UseExceptionHandler("/Error");
			// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
			app.UseHsts();
		}

		app.UseHttpsRedirection();
		app.UseStaticFiles();

		app.UseRouting();

		app.UseEndpoints(endpoints =>
		{
			endpoints.MapBlazorHub();
			endpoints.MapFallbackToPage("/_Host");
		});
	}
}

And because of that, we can add server-side tools, such as Entity Framework.

Now, that's take a look at the Program class in a Blazor WebAssembly application.

// Program.cs
public class Program
{
	public static async Task Main(string[] args)
	{
		var builder = WebAssemblyHostBuilder.CreateDefault(args);
		builder.RootComponents.Add<App>("#app");

		builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

		await builder.Build().RunAsync();
	}
}

It's a lot more slimed down then in a Blazor Server application.

It has support for dependency injection, but not a lot else.

If we want to add server-side functionality to our Blazor WebAssembly application, we will need to integrate it with a server-side application, such as a ASP.NET Core Web API.

#4: Offline Support

What happens when a Blazor application goes offline?

With Blazor Server, once it has lost connection to the server, it is unable to work. It displays a "Attempting to reconnect to the server" message to the user.

Message When a Blazor Server App Goes Offline

Message When a Blazor Server App Goes Offline

But, that's not the case with Blazor WebAssembly!

Once the application has been downloaded to the browser, we can continue to browse our application, even if we have turned off the application.

Obviously, if we are relying on server-side functionality through an API, that would still need to be online for the application to work.

But, it is possible to run a Blazor WebAssembly application offline.

Which Hosting Model to Use?

Deciding on which hosting model to use is down to your requirements.

You can see the differences in our video below.

If you want an application that is supported by search engines, or has server-side support within the application, Blazor Server is your choice.

But, if you want an arguably quicker application that works offline, then you will be looking at Blazor WebAssembly.

Both have their pros and cons. But the one good thing is that Blazor has this support for different requirements.