Blazor is an experimental single-page application (SPA) framework that runs on .NET in the browser.
Unlike prior efforts at getting C# to run client-side, Blazor isn’t transpiling or doing any other fragile tricks: instead, it’s got an actual .NET runtime that loads and runs standard .NET assemblies via WebAssembly (or asm.js for older browsers). This means you get full-fidelity .NET – everything behaves exactly like .NET on the desktop/server.
If you want a demo of what it’s like to build an app with it, watch 5 minutes of this video from NDC Oslo.
I’ll say this again later, but to be sure you’re clear: this is an experiment, and it’s not an official Microsoft product.
Backstory: it started with DotNetAnywhere (DNA)
Back in April, I was trying to think of ways to run .NET under WebAssembly, when coincidentally I stumbled across an HN comment about DotNetAnywhere (DNA), a .NET runtime I’d never heard of before. A quick look at its GitHub repo showed that it’s incredibly compact – the whole implementation is just a handful of plain C files. Its extreme simplicity meant that, even though it well predates WebAssembly and hadn’t even been maintained for over 5 years, it only took a few hours and a few minor tweaks to get it compiled as a WebAssembly binary. To my great surprise, it loaded and executed simple .NET assemblies on the first attempt without any complaints.
Blazor, an app framework
Blazor takes this basis and lets you build an app with it. It uses Razor files, which combine C# and HTML markup, to define components that present your data and update when anything changes (a bit like React or Angular components). It also inherits Razor Pages concepts such as layouts and so on.
This is purely experimental. You can’t build a production application with this, for so many reasons. It exists as a way of finding out what a .NET-based SPA framework might look like, and whether people would have any interest in it.
Nonetheless, some folks from the ASP.NET team and some community members have become interested and contributed a bunch of great enhancements, such as ncave doing some very impressive low-level work to improve DNA, and David Fowler and Stephan Halter from the ASP.NET team getting prototype debugging support working as part of a team hackathon event.
Hitting limitations in DNA
It’s extremely impressive that Chris Dunelm single-handedly created an incredibly compact .NET runtime, so compact that the whole thing (including assembly execution, garbage collection, threading) compiles down to 60KB of WebAssembly. Yes, seriously, 60KB – that’s not a typo – and it does actually work. For more about DNA, see Matt Warren’s post.
But it’s probably not the future. Chris stopped working on DNA about 6 years ago, so it’s a long way behind a modern .NET runtime. It lacks some critical things such as proper reflection support and working with netstandard assemblies, and there are some known bugs such as crashing with certain types of generic method invocations. And when it crashes, it gives you basically no clue about why.
During the ASP.NET team hackathon, the thing that most commonly frustrated and slowed people down was not being able to rely on having the complete standard .NET base class library, and not really knowing what runtime features were supported. So .NET in the browser can only be viable if there’s a true, robust, complete production-grade runtime that can run on WebAssembly/asm.js. But where would a miracle like that come from?
Mono on WebAssembly
Not content with just running Mono on all desktop/server platforms, plus iOS/watchOS, Android, smart TVs and the like, Miguel de Icaza from the Mono team has announced a plan to bring it to WebAssembly. And now, Rodrigo Kumpera is just one pull request away from getting WASM-capable Mono interpreter support merged into mono:master. This is exactly what’s needed: a proper, performant, robust, and feature-complete modern .NET runtime on WebAssembly – under active development by a whole team, no less 🙂
Blazor on Mono
Based on Rodrigo’s excellent work, I’ve migrated Blazor to run on Mono. The result is that it has the same features as before, minus the prototype debugging support, but now it executes faster and it supports a vastly more complete .NET API surface, and virtually every aspect of the runtime works correctly like on desktop/server. It even (usually) provides sensible error messages if you cause unhandled exceptions.
If you want to try it out, install the prerequisites:
VS2017.3 or later
.NET Core 2.0 SDK
… and then install the 0.3.0 (or later) build of Blazor.VSExtension.vsix, the VS project template. Then you can do File->New Blazor application and follow along building an app like in this demo.
As mentioned before, this is not intended for production use – it’s purely experimental. So let me know what you think of it!
Apologies to non-VS users – although this technology is completely cross-platform, I haven’t yet created a dotnet new template for it, so at the moment there is only a VS project template.
As a result of this migration to Mono, the default Blazor app size has exploded from the reasonable 300KB it was on DNA (which included the runtime, core libraries, application code, etc.) to an almighty 4MB. This is because we’re not yet performing IL-stripping on the builds (i.e, the .NET equivalent of tree shaking), and the Mono runtime is bundling a great many desktop-specific features that are irrelevant on the web. And it’s not even minified. I expect that when we optimise the builds, this size will come down substantially.