Blazor – You Want To Run .NET Where?!

Today’s header image was created by Ahmad Dirini at Unsplash
Two Notes From The Future
Note One:
This article was written shortly after Blazor version 0.1.0 was released. Things have changed since then
in fact, I’m adding this update on April 18, 2018, hours after 0.2.0 has been released
As such, some of the code listings and links in this article only work with version 0.1.0.
Note Two:
I’ve taken my PokeBlazor app (which I reference a bunch of times in this post), and uploaded it to Azure. So if you want to see what the finished code looks like, then click here
A Quick Warning
I just wanted to say: this post is going to be a long one.
Unless you’ve been living under a rock for the past few weeks, you’ll have seen the announcement regarding Blazor being in released as a public review.
here’s a link to that announcement – which was made on March 22, 2018
It was also the subject of this week’s ASP.NET Community Standup, here’s a YouTube embed:
I’ve actually written about Blazor twice already
and hosted a mini lab/experiment session
on the blog for the company that I work for:
That’ll be the only time I bring up my employer in this post, I just wanted to point out that I’ve been playing with Blazor a fair bit already
What’s It All About
Cast your mind back to August of 2017, when I shared the following image (taken from one of the many .NET Core 2.0 announcement posts:

This image was all about showing that you could run .NET on any platform, thanks to the wonderful work of Immo Landwerth and his team
they work on the .NET Standard
But there was one place that you still couldn’t run Blazor: in the web browser.
You may be asking yourself, “why?” I’ll (jokingly) answer with a quote from Ted Kennedy:
Some men see things as they are, and ask why. I dream of things that never were, and ask why not.
In a world where we have JavaScript on the server, what would be the harm of running a (primarily) desktop framework in the browser?
nothing, I tell you. Nothing
After all, running .NET in the browser is not a new idea. In fact, Blazor is actually based on an older, open source, experiment called “DotNetAnywhere“. This is something that Steve Sanderson (the “inventor” of Blazor) was very quick to point out in his NDC Oslo 2017 talk on the matter:
How Does It Work?
The short answer is: an ASP.NET Core middleware
you remember what they are, right?
is added to your project which takes the start point of another .NET app; this second app is then run by WebAssembly in the browser.
The long answer is:
Blazor is provided as an ASP.NET Core middleware, the middleware is added to an ASP.NET Core application and does the following at boot:
- loads
blazor.js
which - loads
mono.js
which provides two way communication between your browser and WebAssembly - loads
webasm.js
which loads WebAssembly and (on the instruction of mono.js) sets up a .NET environment - loads your compiled .NET application
- runs the .NET application
this is the paraphrased version
The first thing you might be thinking is, “but how does the UI work?” That’s where Blazor Components come in. They look a lot like Razor Pages, but are rendered differently (due to the Render Tree Builder).
Requirements
Before we see Blazor in action, it’s worth pointing out that there are a few provisos to working with Blazor right now.
The information in this section was correct at the time of this blog post going live
In order to get access to the Blazor templates (for the dotnet new
CLI) you’ll need to run the following command in the terminal:
dotnet new -i Microsoft.AspNetCore.Blazor.Templates |
You can then confirm that they were installed correctly by running:
dotnet new --list |
which should give you something like:
Templates Short Name Language Tags | |
----------------------------------------------------------------------------------------------------------- | |
Console Application console [C#], F#, VB Common/Console | |
Class library classlib [C#], F#, VB Common/Library | |
Unit Test Project mstest [C#], F#, VB Test/MSTest | |
xUnit Test Project xunit [C#], F#, VB Test/xUnit | |
Blazor (hosted in ASP.NET server) blazorhosted [C#] Web/Blazor/Hosted | |
Blazor (standalone) blazor [C#] Web/Blazor/Standalone | |
ASP.NET Core Empty web [C#], F# Web/Empty | |
ASP.NET Core Web App (Model-View-Controller) mvc [C#], F# Web/MVC | |
ASP.NET Core Web App razor [C#] Web/MVC/Razor Pages | |
ASP.NET Core with Angular angular [C#] Web/MVC/SPA | |
ASP.NET Core with React.js react [C#] Web/MVC/SPA | |
ASP.NET Core with React.js and Redux reactredux [C#] Web/MVC/SPA | |
ASP.NET Core Web API webapi [C#], F# Web/WebAPI | |
global.json file globaljson Config | |
NuGet Config nugetconfig Config | |
Web Config webconfig Config | |
Solution File sln Solution | |
Razor Page page Web/ASP.NET | |
MVC ViewImports viewimports Web/ASP.NET | |
MVC ViewStart viewstart Web/ASP.NET |
your list of templates returned will differ, based on the templates that you have installed
In order to compile Blazor applications, you will need to install the latest preview of the .NET Core SDK, this is because the current RTM versions of the SDK don’t support it. To do that, head over to this page and download the package for your operating system
at the time of writing, the latest preview was for 2.1.300-preview1
If you are using Visual Studio (on Windows), then you will need to download the latest preview of Visual Studio 15.7, which can be downloaded at this page. You’ll also need to install this Visual Studio extension in order to access the new templates in VS 15.7 Preview.
There is an ongoing discussion on the OmniSharp GitHub repo about implementing Blazor support, as such there is no support from those folks just yet
they do take pull requests, though 😉
If you’re using Visual Studio for Mac, then I would suggest using a different IDE and the terminal for now. But that’s only because there is no official word about Blazor support for it yet.
During this week’s ASP.NET Community Standup, Dan Roth mentioned that VS for Mac tooling and support is something that they are aiming for with the next release of the SDK.
Rider also has no native support for Blazor. Although I’ve found it much easier to use Rider to edit my Blazor projects
yes, projects. Plural
with Rider and run them with the terminal.
I’d recommend choosing whichever option you’re most comfortable with. As we’ll see, Blazor requires a bit of a shift in mind set.
Let’s Make a Blazor App
We’ll start from nothing and add create a brand new Blazor app. We’ll have it communicate with an external API, as that’s one of the things that Blazor is fantastic for. We’ll use the Pokemon API
you do know that I’m a big video games nerd, right
and we’ll throw in a little semantic ui, just to keep things interesting.
I’ll also be using the terminal (command prompt in Windows) to build and run the app, and Rider to edit the source code. Feel free to use whatever you’re most comfortable with.
I’ve already pushed this code (and a little more) to a public GitHub repo so if you want to read through it, you can do so here. We’re not going to cover all of the code in that repo, just the basics in order to get us going
I’ll talk through the code needed to search for and display the basic data of a Pokemon
A New Project
In the terminal issue the following command:
dotnet new blazorhosted --name pokeBlazor |
This will create the exact structure that we need for the Blazor application (including a solution file). Open the solution file with your editor of choice
or open the directory with VS Code
and you should see a solution layout which looks a little like the following:
I took this screenshot from within Rider, if you’re using a different IDE then it will look slightly different.
If you run the application, you’ll notice something very familiar – if you’ve used the SPA templates before, that is:

Running From the Terminal
In order to run the application from the terminal, you’ll need to change into the server directory
more on the individual projects in a moment
and run from there. The commands you’ll need to use (assuming that you’re in the pokeBlazor
directory) are:
cd pokeBlazor.Server | |
dotnet run |
Break It Down
We have three projects in this Blazor application:
- Client
- Server
- Shared
Starting from the bottom up…
Shared
This project is a .NET Standard 2.0 class library and is meant to be used to store any POCOs which you require for both the Server and Client projects
more on those in a moment
I haven’t tended to use the Server for anything other than serving my Client app in my Blazor apps, so I don’t tend to have a reference to it in the Server. The default template will have a reference to it – in order to use theWeatherForecast
class.
But what’s great about this pattern is that you’re using the same POCO on the server and in the client. You no longer have to keep two separate models (one in C# and one in TypeScript) in sync
fantastic
Client
This is the application which will be compiled and run in the browser. It (currently) makes calls to the server project’s API in order to get data for the “Fetch Data” page, and hydrates the response into an instance of the WeatherForecast
class.
The compiled output of this class will be run on the Server. Any time that you make a change to the Client project, you’ll need to stop the entire solution and start it again.
this is a key point and throws a lot of people when they start working with Blazor
The Blazor team are looking to change this in the next few releases, by leveraging similar technology behind hot module swapping.
Server
The server will serve HTML and JS which will bootstrap a .NET environment in your browser. It will then serve your compiled Client application to the browser, and run it. Almost all of the magic required to get the application to start will be handled for you.
Request ‘Em All
We’re about to break the application by making the Client request information from the Pokemon API. This is an amazingly well documented RESTful API for all sorts of Pokemon data. If you want, you can take a few moments familiarising yourself with it before we begin.
If you’re using VS Code or Rider, you’ll already be seeing some syntax errors. You can ignore them, as long as you were able to run the application earlier
now would be a good time to double check that it still runs
Step One – Clean Up
There isn’t much in this application that we don’t need but let’s remove it anyway, otherwise it might get in the way of our very important work.
Firstly delete the WeatherForecast.cs
class from the Shared project
and watch the syntax errors come in
Then remove the Controllers directory from the Server project and the following lines from it’s Startup.cs:
app.UseMvc(routes => | |
{ | |
routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}"); | |
}); |
We only need the Server to serve our Client application (i.e. we no longer need the API that the server project supplied).
Also remove the references to pokeBlazor.Shared.csproj
in the pokeBlazor.Server.csproj file by removing the following line:
<ProjectReference Include="..\pokeBlazor.Shared\pokeBlazor.Shared.csproj" /> |
In the Client application delete the Pages
and Shared
directories, rename App.cshtml
to be Main.cshtml
and clear it’s contents.
Alter Program.cs file (in the Client project) to read:
using Microsoft.AspNetCore.Blazor.Browser.Rendering; | |
using Microsoft.AspNetCore.Blazor.Browser.Services; | |
using Microsoft.Extensions.DependencyInjection; | |
using PokeBlazor.Client.Services; | |
namespace pokeBlazor.Client | |
{ | |
public class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var serviceProvider = new BrowserServiceProvider(configure => | |
{ | |
configure.AddSingleton<PokeState>(); | |
}); | |
new BrowserRenderer(serviceProvider).AddComponent<Main>("app"); | |
} | |
} | |
} |
Ensure that the _ViewImports.csthml file (in the Client project) reads:
@using System.Net.Http | |
@using Microsoft.AspNetCore.Blazor | |
@using Microsoft.AspNetCore.Blazor.Components | |
@using Microsoft.AspNetCore.Blazor.Layouts | |
@using Microsoft.AspNetCore.Blazor.Routing | |
@using pokeBlazor.Client | |
@using pokeBlazor.Client.Services |
Remove the following (highlighted lines) in the index.html
file (found in the wwwroot directory):
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>pokeBlazor</title> | |
<base href="/" /> | |
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /> | |
<link href="css/site.css" rel="stylesheet" /> | |
</head> | |
<body> | |
<app>Loading...</app> | |
<script src="css/bootstrap/bootstrap-native.min.js"></script> | |
<script type="blazor-boot"></script> | |
</body> | |
</html> |
Finally delete the bootstrap
and fonts
directories from the wwwroot directory’s css subdirectory.
Your Blazor solution layout should look something like this:
Step Two – Let’s Add A Component and a Service
Blazor Components, if you don’t know, use Tag Helpers to add components to a page. The tag helpers are auto expanded, and their rendered content are added to the page, during the Render Tree Builder’s work.
Tag Helpers look a little like HTML tags, but they aren’t valid HTML tags, as we’ll see in a moment.
Creating a Component
Create a directory in the Client project called Components, create a file called RandomPokemonSearch.cshtml
, and paste the following code into it:
<div class="ui grid"> | |
<div class="row"> | |
<div class="ui two column centered grid"> | |
<h1>PokeyMans Decks</h1> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="ui two column centered grid"> | |
<p>Enter the ID of a PokeyMans in the input box and click on `Search` to find out about that PokeyMans</p> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="ui two column centered grid"> | |
<input type="text" @bind(PokemonId) /> | |
</div> | |
<div class="ui two column centered grid"> | |
<button @onclick(() => OnGetPokemon(PokemonId)) type="button" class="ui secondary button">Search</button> | |
</div> | |
</div> | |
</div> | |
@functions | |
{ | |
public Func<string, Task> OnGetPokemon { get; set; } | |
public string PokemonId { get; set; } | |
} |
Most of this file reads like standard HTML, right up until the @functions
section. This is where the Blazor Components stuff comes in.
Essentially the @functions
section is a C# class. What we’ve done is inlined something like the following:
namespace pokeBlazor.Client | |
{ | |
public class RandomPokemonSearch | |
{ | |
public Func<string, Task> OnGetPokemon { get; set; } | |
public string PokemonId { get; set; } | |
public RandomPokemonSearch() | |
{ | |
} | |
} | |
} |
but we’ve also made the properties of this class available throughout the RandomPokemonSearch
component. This is what the @bind
directives are for (we’re binding the controls in the markup to the properties of the class).
Handling State with a Service
We need to add a service to the Client project. The service that we’ll create holds the state of our Client app when running in the browser
remember that http is stateless
Create a directory in the Client project called Services, add a file called PokeState
to it, and add the following code to that file:
using System; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Blazor; | |
using pokeBlazor.Shared; | |
namespace pokeBlazor.Client.Services | |
{ | |
public class PokeState | |
{ | |
public Pokemon PokemonSearchResult { get; private set; } | |
public bool SearchInProgress { get; private set; } | |
// Lets components receive change notifications | |
public event Action OnChange; | |
// Receive 'http' instance from DI | |
private readonly HttpClient http; | |
public PokeState(HttpClient httpInstance) | |
{ | |
http = httpInstance; | |
} | |
public async Task GetPokemon(string id) | |
{ | |
SearchInProgress = true; | |
NotifyStateChanged(); | |
PokemonSearchResult = await http.GetJsonAsync<Pokemon>($"https://pokeapi.co/api/v2/pokemon/{id}/"); | |
SearchInProgress = false; | |
NotifyStateChanged(); | |
} | |
private void NotifyStateChanged() => OnChange?.Invoke(); | |
} | |
} |
This is almost everything that we need to do for this step
we’ll go through what all of this code does in a moment
We just need to add the Pokemon
class and use the RandomPokemonSearch
component in the Main.cshtml
file.
The Pokemon Class – Gotta Represent ‘Em All
The Pokemon class will be based on the data returned when you issue a request to the Pokemon API for a given critter. The information returned for Bulbasaur, for example, looks like this:
{ | |
"name":"bulbasaur", | |
"weight":69, | |
"location_area_encounters":"\/api\/v2\/pokemon\/1\/encounters", | |
"height":7, | |
"is_default":true, | |
"base_experience":64 | |
} |
I’ve removed a lot of information here. For the full response, issue a request from your browser or click the link above this code block.
Create a file called Pokemon.cs
in the Shared project and paste this code into it:
namespace pokeBlazor.Shared | |
{ | |
public class Pokemon | |
{ | |
public int id { get; set; } | |
public string name { get; set; } | |
public bool is_default { get; set; } | |
public int base_experience {get; set;} | |
public int weight {get; set;} | |
public int height {get; set;} | |
} | |
} |
Caveat
We want the application to download to the browser as quickly as possible, so I’ve intentionally ignored the C# standard for public properties. I could have included Newtonsoft.Json so that I could have well named C# properties and have them mapped to the JSON data nicely, but Newtonsoft.Json is huge.
That’s not a negative against Newtonsoft.Json, as it does a lot of stuff. But I don’t need most of the stuff that it provides, so I’ll leave it out for now.
When you’re finished with this blog post, feel free to add NewtonSoft.Json and the relevant attributes to automatically map from the JSON to the POCO and see just how much longer the app takes to download
if you wish
Using Our Component
Over in the Main.cshtml
file (in the Client project), add the following code:
@inject PokeState state | |
<div id="search-and-results-area"> | |
<div id="search-area"> | |
<RandomPokemonSearch OnGetPokemon=state.GetPokemon/> | |
</div> | |
</div> | |
@functions | |
{ | |
protected override void OnInit() | |
{ | |
state.OnChange += StateHasChanged; | |
} | |
} |
But What Did I Just Do?
If you run the Blazor application
remember to stop and start it if it’s still running from eariler
you’ll see a pretty ugly screen (once the compiled binary and the linked namespace binaries have been served to your browser fully):

Once the Client application had been downloaded, it was started via the Main
method in the Client project’s Program.cs. This method does two things:
- Add an instance of the PokeState class as a Singleton
- Add the contents of the
Main.csthml
file to the body tag in the HTML which was served from the Server project
The Main.cshtml
file was then put through the Render Tree which did the following actions:
- Injected the PokeState singleton into the C# class
- Created an OnInit method and set up a delegate to the OnChange event
- Inlined the rendered content of the
RandomPokemonSearch
component - It also set the value of the
OnGetPokemon
method on theRandomPokemonSearch
component to theGetPokemon
method (fromPokeState
)
The RandomPokemonSearch.csthml
file was then rendered by the Render Tree, which did the following:
- The value of
PokemonId
was bound to the input text box - The
onclick
method for the button was bound to theOnGetPokemon
method
actually parts of these two steps happen in the opposite order, but it’s easier to think about it this way
When the button is clicked, Blazor will call the GetPokemon
method on the PokeState
service. This service acts as our state provider, as such we set up an Action
which acts as a sort of callback. This action will tell the BrowserRenderer
class that it need to re-render the HTML being served on the browser.
When this happens, the Main.cshtml
file (and all of the components used in it) are put back through the Blazor Render Tree and the HTML is swapped out in the browser.
Just. Like. Magic.
Can We Make The App Better?
Let’s add the semantic ui files.
In the Client project’s wwwroot directory, add two subdirectories:
- CSS
- JS
In the CSS directory, create a subdirectory called `semanticui`, and add the version of the semantic-ui.min.css file found in the GitHub repo for this project.
In the JS directory, create a subdirectory called `semanticui`, and add the version of the semantic-ui.min.js file found in the GitHub repo for this project.
Then edit your index.cshtml
file (in the Client project’s wwwroot subdirectory) to look like this:
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<title>DwBlazor</title> | |
<base href="/" /> | |
<link rel="stylesheet" type="text/css" href="css/semanticui/semantic.min.css"> | |
<link rel="stylesheet" type="text/css" href="css/site.css"> | |
<script | |
src="https://code.jquery.com/jquery-3.1.1.min.js" | |
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" | |
crossorigin="anonymous"></script> | |
<script src="js/semanticui/semantic.min.js"></script> | |
<script type="blazor-boot"></script> | |
</head> | |
<body> | |
Please wait... | |
</body> | |
</html> |
I’ve highlighted the important lines that you’ll need to copy in
Then stop and start the application and the UI should look a little better:

Just One More Thing
The last thing we’ll do is render the data which was parsed from the Pokemon API response.
It’s the Final Component
Create a new component called RandomPokemonResult
and paste the following code into it:
@using pokeBlazor.Shared | |
@if (PokemonToDisplay != null) | |
{ | |
<div class="ui grid"> | |
<div class="row"> | |
<div class="ui two column centered grid"> | |
<h2>@PokemonToDisplay.name</h2> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="ui two column centered grid"> | |
<div class="two wide column"> | |
<label>Weight: @PokemonToDisplay.weight</label> | |
</div> | |
<div class="two wide column"> | |
<label>Height: @PokemonToDisplay.height</label> | |
</div> | |
<div class="two wide column"> | |
<label>Base Exp: @PokemonToDisplay.base_experience pt</label> | |
</div> | |
</div> | |
</div> | |
</div> | |
} | |
@functions | |
{ | |
// Parameters | |
public Pokemon PokemonToDisplay { get; set; } | |
} |
Then edit the Main.cshtml
file to read like this:
@inject PokeState state | |
<div id="search-and-results-area"> | |
<div id="search-area"> | |
<RandomPokemonSearch OnGetPokemon=state.GetPokemon/> | |
<RandomPokemonResult PokemonToDisplay=state.PokemonSearchResult/> | |
</div> | |
</div> | |
@functions | |
{ | |
protected override void OnInit() | |
{ | |
state.OnChange += StateHasChanged; | |
} | |
} |
Finally stop and start the application again, enter “1” in the text box and click the “Search” button and you should get something like the following:
keep going with other non-negative IDs and see which Pokemon you find
Conclusion
Together we just created an incredibly useful Blazor application
ok, I’m probably inflating the app’s importance there. I mean, it’s never going to win any awards or change the world. But a man can dream, though.
We learnt about how Blazor does its thing, how to create a Blazor app from nothing, and how to use it to talk to an external API.
There’s a lot more to Blazor
which I might cover in a later blog post
and how amazing it is. But I’ll stop this post here, as it’s pretty long already.
Have you used Blazor for anything yet? If so, what did you build? If not, why not? It’s super easy to use.
Also, take a look at the GitHub repo that I built alongside this blog post. It’s more complete than the example that we built together. Plus, it has a few issues for the known bugs with the application
because there are a few