Blazor is a new web framework that allows you to create fully interactive web apps using C#. Using the magic of a .NET runtime compiled for WebAssembly, you can even run Blazor entirely on the client—you don’t have to use JavaScript frameworks to create your applications anymore.

What Is Blazor?

Blazor is the latest feature of ASP.NET Core, Microsoft’s 20 year old web framework. Despite being old, Microsoft still maintains it, and ASP.NET has been consistently improving along with C# and the .NET runtime as a whole.

Razor pages, and ASP.NET’s old MVC model, both allow you to generate data-driven HTML pages using C#. That’s been around forever, but what it’s always lacked is interactivity. It’s pretty hard to make a web app when you have to reload the page to view changes.

So, Blazor solves that by directly linking the server and client with a library that can modify the DOM at runtime, and brings in many of the component lifecycle methods and update handlers that you’d expect out of a framework intended to compete with React.

And, with Razor page’s minimalist syntax, it makes coding in Blazor a breeze:

Blazor has two main modes of operation, the coolest of which is Blazor Client, which packages .NET itself into a framework that can be run entirely on WebAssembly. WASM is basically MSIL for the web; it’s a lightweight binary instruction format that any language can compile to, even “desktop” languages like C++ and Rust.

So how is performance with this? Well, currently it’s using an interpreter, as native AOT compilation for .NET is still being worked on. But that will improve eventually; the main downside of Blazor Client is longer download times—DLLs can be big files by web standards, and they all need to be loaded to get the application up and running. However, large JS frameworks also have this problem, and is a big reason why server-side rendering is popular.

It makes up for that download time by being very fast to refresh pages and navigate around the app, considering it doesn’t have to wait for the server to do so.

If you want to use a more traditional hosting model similar to React’s Server Side Rendering (SSR), that option is also available to you. It’s more performant, and comes with the benefit of running code on a trusted server.

To achieve this, Blazor Server can connect to the client using a SignalR connection, which is just a fancy wrapper over WebSockets that can also fall back to HTTP if it needs to. This does put more stress on the ASP.NET server than traditional web hosting, as it needs to re-render and re-send every single HTML change to all connected clients. If you have thousands of people connected, this can be an issue when scaling up.

While Blazor is currently a web framework, Microsoft is also making Blazor Desktop, which functions a lot like Electron does by packaging web UIs into desktop applications, as well as Blazor Native, which will be able to render native UIs on mobile operating systems. Microsoft seems to think of it as their next application programming model for making interactive frontends on any platform.

Hybrid Mode

Blazor can also be used in a “hybrid mode” using prerendering. Blazor WASM can display raw HTML while the framework loads, usually used for a loading bar or spinner wheel. But, if you host the app from ASP.NET, you can render the Razor pages from the server before you even send the app to the client.

This works perfectly, with the catch that the page will not become interactive until Blazor actually loads. It usually only takes a second though so this isn’t really an issue, besides some quirks with reloading data twice.

With this setup, you get the best of both worlds— your app loads quickly, with no loading screen, and it’s lightning fast to navigate around. This feature is still being worked on, and comes with a lot of quirks, but as of .NET 6 preview 6, it is working, and you can read more at Jon Hilton’s guides, parts one and two.

One of the quirks is that WASM apps relying on an API will have to have two implementations of each service, on the client and server, so that the server can talk to itself to fetch the information when it pre-renders. This results in some flashing when WASM loads and does its own data fetching, but this can be fixed in .NET 6—this guide shows how to persist component state so that your app will seamlessly transition from the fake “loading page” to the real application.

Setting Up Blazor

Luckily Visual Studio provides generators and you don’t have to set this all up yourself. Open Visual Studio, and create a new project. Search for “Blazor” and select either Blazor WebAssembly or Blazor Server.

We’ll go with Blazor WebAssembly here, as Blazor Server is simpler and just includes both the client and server in the same project.

Give it a name and select your framework. One thing to note is that Blazor WebAssembly technically doesn’t even need a server at all; you can just host it as a static website on NGINX or even an AWS S3 bucket. But, if you’re connecting to an API to talk to a database, you might as well make that API bundled with the client, as you can share code between them and of course use the same language.

You solution will be set up with three projects, a client application, an ASP.NET server API and web host for the client, and a shared library between them.

If you click launch, you’ll see ASP.NET boot up and serve the web page. If you’re using Blazor Server, it will connect to ASP.NET over SignalR to handle interactions.

Of course, Blazor WebAssembly will only send requests to the server when made explicitly by the application.

A Tour Of The Blazor Environment

Let’s take a tour of the application. Starting with the client, the main entry point is Program.cs, which creates the WebAssemblyHost, adds the root App.razor component, then builds and runs the app.

Technically, the entry point is wwwroot/index.html, which loads Blazor’s JavaScript file, shows a loading page while Blazor initializes, and shows an error message if it doesn’t.

App.razor handles routing of pages using a Router component. This takes in the assembly and loads all pages marked with the @page name attribute. You can learn more about routing in Razor pages here.

The router loads the MainLayout.razor component, which extends LayoutComponentBase. That loads the NavMenu.razor component alongside the body, and displays your application.

Great! As for the server, it’s a standard ASP.NET application. It creates a host builder, and adds services configured in Startup.cs. Notably, it configures it for WASM debugging, serves the Blazor Framework files, and configures its own Razor pages and controllers to serve JSON content.

If this was just a Blazor Server app, it wouldn’t need this separate API, and could just fetch data from an internal service. But since it isn’t, it needs to expose that service over the wire, in the form of a ASP.NET ApiController that specifies handler methods for different HTTP actions.

The models for this are shared between client and server, in the shared project.

Fixing Microsoft’s Awful Color Choices

Before sitting down to code, we need to fix something. For some reason, Microsoft’s default color choice for C# HTML directives in Razor pages is using what is perhaps the worst color combination imaginable—light purple text on a light tan background.

Luckily you can change it from Tools > Options:

Under Environment > Fonts and Colors, select “Razor Directive” and change the background color to something more reasonable. You probably still want it to stand out, so I just chose pure black, which will be noticeable but non-intrusive.

You’ll also need to change “HTML Server-Side Script,” (which is technically now an outdated name considering Blazor WebAssembly’s existence).

And with that simple fix, you can save your eyeballs hours of pain.

Serving Dynamic Content

The last file you’ll want to check out is on the client, FetchData.razor. This is where the client actually consumes the server-side API, with the following data-driven page:

This is a fairly complex Razor page, so it’s a good example for us to break down here.

To start, it specifies a manual override for the page route with @page “/fetchdata”. It then imports the shared models from the shared project, and also uses dependency injection to give it an HttpClient, which was set up in Program.cs.

We’ll skip down to the bottom to explain this first—the @code block contains the actual C# code for this page. In it, there’s a private variable called forecasts. This is initially null, but when the page is initialized, it makes a web request to grab the data from the API and deserialize it.

When that variable is updated, Blazor detects the change and re-renders the page. The page itself is everything in between, which starts with a header and description, but then contains an @if statement. This is C# conditional HTML, and in this case is used to show loading text while Blazor is making the request to the API. Then, once it finishes and re-renders, forecasts won’t be null, and it will render the table that will do @foreach element in the list, and render a table row.

Using this, you can render dynamic content from your models. To support more advanced CRUD operations, and more dynamic UIs, you will need to use buttons and inputs. You can use