September 2018

Volume 33 Number 9

[Cutting Edge]

Never Mind JavaScript, Here’s Blazor

By Dino Esposito

Dino EspositoAbout a decade ago the mainstream Web stopped at a crossroad. Traditionally interpreted, client-side technologies such as HTML, CSS and JavaScript were about to disappear, progressively overwhelmed by compiled technologies and languages such as XAML and C#. At the same time, the browser environment seemed poised to incorporate a native, dedicated processing engine like Silverlight, which had been installed as a separate plug-in. Then the first drafts of HTML 5 appeared at the horizon and, shortly thereafter, Silverlight was sunsetted.

The turn of events shook up the landscape as IT decision makers sought a viable platform for cross-platform Web development. HTML5 received a boost and JavaScript began its comeback. Today, Angular, React and Vue are highly popular JavaScript-based frameworks that more and more development teams are choosing for building their front ends.

Blazor comes up as a possible alternative to Angular/React/Vue and, thanks to WebAssembly (WASM), it opens up the Web to be able to take advantage of existing development ecosystems, including .NET. Therefore, more than just another Model-View-ViewModel (MVVM)-oriented JavaScript framework, Blazor is, to some extent, a modern attempt to revamp and refine the Silverlight concept—bringing the power of C# to client-side Web development. The core of Blazor is designed to provide a strongly typed, browser-based environment upon which to build Web front ends using C# and .NET Core, in lieu of JavaScript and Razor on top of HTML. However, Blazor doesn’t push HTML and CSS to the corner. Rather, it extends the HTML syntax with a collection of predefined Razor tag helpers while requiring no plug-in to be installed.

I caution that Blazor is still largely in development and whatever you read here may radically change in only a few weeks. The code presented in this article is based on version 0.5.0 released in July 2018.

In this article, I’ll discuss the underlying system architecture of a Blazor application and present a minimal “Hello World” application.

The Magic of Blazor

If you’re coming from a Silverlight background, you might wonder how Blazor—a non JavaScript  platform—can run in the browser without an installable plug-in. The answer is that, well, it can’t. Blazor actually requires some sort of plug-in to host it within a compliant browser. The trick is that the so-called conceptual plug-in is already embedded in most modern browsers (those released in the past 12 months), and can be easily polyfilled via JavaScript in older browsers. Unlike discreet plug-ins like Adobe Flash or Silverlight, the tool enabling Blazor support is WASM, an open standard being developed in a W3C Community Group that includes representatives from all major browsers.

Technically, WASM is a binary format for a stack-based virtual machine (VM), architecturally similar to the .NET CLR and Java Virtual Machine, but unlike the Android Dalvik VM. As the compilation target of high-level programming languages, WASM has the potential to enable deployment of .NET applications over the Web. For this to happen, however, a bridge is needed to convert the .NET runtime to WASM. Blazor relies extensively on work done by Xamarin to bring its Mono framework to WASM. The .NET code contained in a Blazor application runs against a version of Mono specifically compiled to WASM, as shown in Figure 1.

.NET Code Running in the Browser
Figure 1 .NET Code Running in the Browser

How is this different from, say, Silverlight? Silverlight applications ran sandboxed in a browser-specific shell communicating with the container browser environment through ActiveX in Internet Explorer, and through NPAPI in other browsers like Chrome and Firefox (see documentation at bit.ly/2klDgdY). Today, most browsers are dismissing NPAPI support in favor of WebAssembly. Blazor takes many of the best concepts of Silverlight and applies them in a way that appeals to developers seeking an alternative to JavaScript.

What about legacy browsers?

Development tools cross compile code to both WASM and asm.js, which is a low-level subset of JavaScript, intended to be a compile target from high-level languages (see asmjs.org). Blazor, in particular, falls back to using an asm.js-based .NET runtime. Then the deployed code performs feature detection in the browser to determine how to run. Note that the entire asm.js framework is currently under research and development.

You can visit caniuse.com to check which browser versions currently support WASM. The site notes that all browser versions (both desktop and mobile) released from mid-2017 and on support it. Note that at the time of this writing, Blazor polyfill was temporarily not working with Internet Explorer.

Anatomy of a Blazor Application

A Blazor application is a plain .NET Standard library with a Program.Main entry point that gets downloaded and run in the browser. Only the .NET runtime is compiled to WASM; the source code you write in C# runs natively as if it were a normal .NET application. To clear security concerns, note that all Blazor code still runs in the same secure sandbox as JavaScript. Figure 2 shows the list of files downloaded by the sample Blazor application being presented in the rest of this article.

Files Downloaded by the Sample Blazor Application
Figure 2 Files Downloaded by the Sample Blazor Application

The different background color you see in the figure identifies two distinct moments in the lifetime of a Blazor application. First, the blazor.js and mono.js files are downloaded to coordinate the download of the Mono WebAssembly runtime (the mono.wasm file). At present, the Mono runtime includes a relatively feature-rich version of .NET and weighs in at 600KB. However, in earlier versions a compact option was available at a fraction of the size. This is an area that could use some improvement and optimization.

Once the Mono runtime has been downloaded, it begins the download of the actual .NET assemblies. The initialization step may take a while—about three seconds in the example in Figure 2. For this reason, the standard Blazor Visual Studio template provides a dedicated area for the UI to show during the loading phase. Let’s take a look at a sample application.

Building a Sample Application

To play with Blazor, you need .NET Core 2.1 and Visual Studio 15.7 or newer. In addition, you need to install the Blazor templates from the Visual Studio marketplace. The template is located under the ASP.NET Core Web Application folder. There are currently three templates—plain client-side Blazor, ASP.NET Core-hosted application and server-side Blazor. Let’s go for a plain Blazor application with no dependencies on any back-end environment. This scenario resembles very closely that of an Angular/React or even Silverlight application—a plain client application downloaded and run within the browser.

As mentioned, the project in Visual Studio is a .NET Standard 2.0 console application based on two specific NuGet packages: Blazor.Build and Blazor.Browser. Both are rooted in the Microsoft.AspNetCore namespace.

The project is a standard .NET Core project with a Program.cs bootstrapper, a Startup.cs class, and a few folders that recall an ASP.NET Core application, such as wwwroot, Shared, and Pages. The Main method is shown as follows:

public class Program
{
  public static void Main(string[] args)
  {
    CreateHostBuilder(args).Build().Run();
  }
  public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) =>
    BlazorWebAssemblyHost.CreateDefaultBuilder()
      .UseBlazorStartup<Startup>();
}

A Blazor application is made of components that each consist of a .cshtml Razor file. By default, the name of the .cshtml file is the name of the component. In the sample application, App is the name of the startup component whose source code is in app.cshtml, as shown here:

<Router AppAssembly=typeof(Program).Assembly />

At the minimum, the startup class indicates the App class to use.

public class Startup
{
  public void Configure(IBlazorApplicationBuilder app)
  {
    app.AddComponent<App>("app");
  }
}

The App module just sets up the Blazor router component. In traditional Web sites (such as ASP.NET), routing takes place on the server, but in single-page applications it’s preferably done via a dedicated client-side component. In Blazor, the router isn’t made by JavaScript (as it is in, say, Angular), but, rather, is an instance of the internal Router class that parses all the classes in the referenced assembly, looking for those that implement the IComponent interface.

The router is responsible for intercepting all navigation activity, both inward and outward, and making it happen. Clearly, Blazor components are expected to provide routing information for the router to invoke them appropriately. Blazor supports the same @page notation of Razor Pages in ASP.NET Core. In addition, it supports the Route attribute for component classes written in plain C#.

The Single Page

Usually, a single-page application starts from an index.html page. A Blazor application is no exception, and the single page is located under the wwwroot folder. The single page is expected to contain at least the following markup:

<app>
  <!—initialization markup -->
</app>
<script src="_framework/blazor.webassembly.js"></script>

The content of the app element is displayed during the initial loading of the Blazor platform, namely the first chunk of files in the list of Figure 2. You can have any valid HTML in the app element, most commonly a loading .gif. The script element is responsible for dynamically downloading the necessary .dll files.

The actual displayed content of the homepage is determined by the router and the remaining content of the index.html file found following the script element. Let’s review the work done by the router.

The router checks the requested URL—the root of the deployed site—and looks for a registered component that can match the root URL. In the sample project, the Pages folder contains an index.cshtml file that begins with the following content:

@page "/"
<h1>Hello, Blazor!</h1>
Welcome to your first BLAZOR app.

The @page directive instructs the router about the template to pick up. If a _ViewImports.cshtml file is found in the Pages folder (and/or the root folder), its content is taken into account. In the sample project, the _ViewImports file in root folder contains a list of using statements, while the _ViewImports file in the Pages folder contains a reference to the layout template:

@layout MainLayout

Subsequently, the content of the MainLayout.cshtml is processed and the @Body placeholder populated with the output of the selected Razor view (index.cshtml). In the sample project, the layout file (found in the Shared folder, as in ASP.NET Core) contains a typical Bootstrap 4 dark navbar element. Here’s that code:

<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  ...
</nav>
<div class="container">
  @Body
</div>

Again, if you’re coming from an ASP.NET MVC background, this programming pattern should look pretty familiar. In the navbar you typically have links. You can express links through the canonical A and BUTTON elements, or use one of the predefined (or custom) Razor tag helpers. In particular, Blazor comes with the NavLink helper component, which provides a friendlier syntax to express links that may or may not be plain URLs. In a single-page application, in fact, a link can be anything that the router can understand. Here’s a fragment of Razor code used in the navbar of the sample application:

<div class="collapse navbar-collapse" id="navbarNav">
  <ul class="navbar-nav">
    <NavLink class="nav-link" href="digitalclock">
      DIGITAL CLOCK
    </NavLink>
  </ul>
</div>

The href attribute points to a URI that can just match the route to a component like “digitalclock,” a separate CSHTML file that fully implements a digital clock component. The digitalclock.cshtml file is found under the Pages folder.

Building a Sample Component

A Blazor component is a self-contained chunk of HTML and C#. Any necessary CSS goes in separate files, reasonably named after the component itself. Note that Blazor doesn’t do anything special with CSS and doesn’t impose any convention. Dealing with CSS is entirely up to you. Here’s a digital clock implemented as a Bootstrap input group:

<div class="clock">
  <div class="input-group">
    <span class="@currentCss">@currentTime</span>
    <div class="input-group-append">
      <button class="btn btn-primary"
              type="button"
              onclick="@startStop">@buttonAction</button>
    </div>
  </div>
</div>

Razor expressions like currentCss, currentTime and buttonAction refer to component fields defined within the @functions section of the file. You can see these here:

@functions {
  string currentTime = "N/A";
  string buttonAction = "N/A";
  string currentCss = "clock-notset";
  Timer timer;
  ...
}

The startStop expression refers to a method being invoked when the Stop or Start button is clicked to start/stop the timer. Figure 3 presents the full code of the DigitalClock component.

Figure 3 C# Code of the DigitalClock Component

@functions {
  string currentTime = "N/A";
  string buttonAction = "N/A";
  string currentCss = "clock-notset";
  Timer timer;
  protected override async Task OnInitAsync()
  {
    InitTimer();
    StartTimer();
  }
  void startStop()
  {
    if (timer.Enabled)
    {
      StopTimer();
    }
    else
    {
      StartTimer();
    }
  }
  private Task TimerTick()
  {
    currentTime = DateTime.Now.ToLongTimeString();
    currentCss = "clock-working";
    this.StateHasChanged();
    return Task.CompletedTask;
  }
  private void InitTimer()
  {
    timer = new Timer(1000);
    timer.Elapsed += async (sender, e) => await TimerTick();
  }
  private void StartTimer()
  {
    buttonAction = "STOP";
    timer.Start();
  }
  private void StopTimer()
  {
    buttonAction = "START";
    timer.Stop();
  }
}

Figure 4 shows the program interface.

The Sample Application in Action
Figure 4 The Sample Application in Action

The demo presents a digital clock backed up by a .NET timer. Data binding is automatic for events triggered via an explicit user action (such as when a button is clicked), but not when the event originates programmatically, such as via a timer. In the latter case, you must call the method StateHasChanged to force the browser renderer to refresh the view. Here’s the code of the timer tick handler within the digital clock Blazor component:

private Task TimerTick()
{
  currentTime = DateTime.Now.ToLongTimeString();
  currentCss = "clock-working";
  this.StateHasChanged();
  return Task.CompletedTask;
}

The full source code can be found at bit.ly/2LVeCxA.

Wrapping Up

Blazor is an upcoming experimental framework for building .NET-based single-page applications running in the browser via WebAssembly. WebAssembly is a sandboxed way to deploy native binaries to a compliant browser—essentially all browsers shipped since mid-2017. Blazor uses Razor and C# to design views and includes a router and a composable user interface like most of the other popular JavaScript frameworks.

This article presents the foundation of a client-side application. In upcoming columns, I’ll explore integration with the specific ASP.NET Core backend and Blazor extensibility points. You can read more about Blazor in Jonathan Miller’s article that guides you through the quite necessary tasks for a client-side application of downloading JSON data from HTTP endpoints.


Dino Esposito has authored more than 20 books and 1,000 articles in his 25-year career. Author of “The Sabbatical Break,” a theatrical-style show, Esposito is busy writing software for a greener world as the digital strategist at BaxEnergy. Follow him on Twitter: @despos.

Thanks to the following technical experts for reviewing this article: Daniel Roth (Microsoft), Jonathan Miller


Discuss this article in the MSDN Magazine forum