A breakdown of blazor project types

Blazor is a single-page web application (SPA) framework built on .NET that runs in the browser with Mono's WebAssembly run-time, or server-side via SignalR. Blazor features a component architecture, routing, a virtual DOM, and a JavaScript Interoperability (interop) API. Currently, Blazor is in an experimental state which allows for rapid development, iterations, and as implied, experimentation.

Blazor shipped 0.1 in March of 2018, and within a few months rolled out 0.5.1. In Blazor's short, roughly six month history it has already launched a variety of project types to on-board developers with varying application needs. In this article well discuss the three project types available as of 0.5.1, we'll get an understanding of what scenarios to apply them to, and what to expect from each. We'll jump in and evaluate the server-side, client-side, and full-stack. If you think you've seen it all, make sure to peek at the Server-Side project type as it may turn out to be quite different that one might expect.

Just so we all get started on the same page, let's begin with Blazor's prerequisites.

Before You Blaze

Blazor is an unsupported experimental web framework that shouldn't be used for production workloads at this time.

As of writing, Blazor is shipping at a rate of once every two months. Because of the project's nature, new tooling must be installed before the Blazor project templates are available in Visual Studio. The same applies to the dotnet command line interface (CLI).

Installation

If you're the type of developer who spends a majority of their time in Visual Studio then you're in luck, Visual Studio is likely to provide the best experience while Blazor is in its infancy, however the dotnet CLI is still quite handy.

Setting up Visual Studio requires the following steps:

  1. Install the .NET Core 2.1 SDK (2.1.300 or later)
  2. Install Visual Studio 2017 (15.7 or later) with the ASP.NET and web development workload selected
  3. Install the latest Blazor Language Services extension from the Visual Studio Marketplace
Important!
The default global.json file included in the Blazor project templates may cause the project to fail to load or run if you don't have version 2.1.3xx of the .NET Core SDK installed. The global.json file pins the project to 2.1.3xx; so if you don't have that specific version range installed, the project fails to load or run even if you have a newer SDK installed. The workaround is to remove the global.json file from the project or install version 2.1.302 of the .NET Core SDK.

This installation process will add the three project types we'll be covering below. Blazor Component Library project, the fourth and final project type, is only available from the CLI at this time. The Blazor Component Library is outside the scope of this article since it isn't an executable project type.

To make the templates available from the dotnet CLI, open a command console and run the following command:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates

"Set Blazors to Run"

With the tooling installed we're ready to run and explore the Blazor projects. The New ASP.NET Core Web Application dialog is where the new project types are found.

To reveal the dialog:

  1. Select File > New Project > Web > ASP.NET Core Web Application
  2. Make sure .NET Core and ASP.NET Core 2.1 (or later) are selected at the top
  3. Choose the Blazor template and select OK

Image of dialog box

Let's breakdown the project types from left to right:

  1. Blazor *Client-Side
  2. Blazor (ASP.NET Core Hosted) *Full-Stack
  3. Blazor (Server-Side in ASP.NET Core) *Server-Side

* Denotes unofficial short description

Now that we know were to find each project template, we can discuss the details of each selection.

Blazor Client-Side

The Blazor client-side template can be compared to an HTML, CSS, and JavaScript application, similar to other SPA frameworks. However, in the case of Blazor, JavaScript is supplemented by .NET and C# via WebAssembly. Unlike ASP.NET MVC projects that use Razor, Blazor (client-side) is not rendered on the server, instead the HTML is delivered to browser via the Blazor framework on the client. So in essence the browser processes everything in this project is a static resource.

Since the project can be treated as a set of static resources, it leads to some interesting possibilities that have yet to be seen in the ASP.NET ecosystem. Projects built with this template can be hosted on virtually any resource than can serve static files, for example: GitHub pages and Azure Storage: Static website hosting.

The template includes examples of how to get started with Blazor as well as basic page layouts, navigation controls, and styling from Bootstrap. The project structure is fairly simple with just the few resources outlined below:

  • /wwwroot: web standard static resources including: CSS, JavaScript, JSON, images, and HTML
  • /Pages: Razor (.cshtml) application pages/features
  • /_Shared: common (.cshtml) components & page layouts
  • App.cshtml: a temporary file, to be removed in later versions of Blazor
  • Program.cs and Startup.cs: application bootstrapping and configuration

At first glance, some familiar concepts may appear as Blazor uses an approach similar to ASP.NET apps. Not only is Program.cs and Startup.cs a common feature in .NET apps, but Blazor also utilizes a similar concept to ASP.NET Core Razor Pages. Blazor application pages or features can be found under the Pages project path, while routing is handled by the page's @page directive. In the Blazor framework, a view or .cshtml is treated as a web component including those marked with the @page directive.

@page "/myRoute"

<!-- component markup -->

@functions { 
  // component logic 
}

All Blazor projects include an Index, Counter, and Fetch Data example pages. These items are consistent throughout all project types, except for Fetch Data, as the key difference between each project type is where the application is hosted in relation to the data it consumes.

Let's begin by examining the Counter page and its component markup and logic.

Counter

The Counter page is a simple component decorated with the page directive. This component demonstrates the basic composition of a Blazor component including: routing, data binding, and event binding/handling.

The counter component uses a basic HTML button to increment a counter field which is displayed within a paragraph tag. Because Blazor operates as a single page application all of the interactions in the component happen on the client. Updates to the browser's Document Object Model (DOM) are handled by the Blazor framework though data binding.

Moving on to Fetch Data page, we'll see how Blazor is capable of handing local data sources.

Fetch Data

In this project type, the Fetch Data page is a component that utilizes data from a local static file. The Fetch Data component demonstrates dependency injection and basic Razor template concepts. This version of Fetch Data is very similar to the example found in the Full-Stack template except for the location in which the data is loaded from.

At the top of the component following the routing directive dependency injection is declared. The @inject directive instructs Blazor to resolve an instance of HttpClient to the variable Http. The HttpClient is then used by the components logic to fetch data using GetJsonAsync which binds data from the JSON request to an array of WeatherForecast objects:

@page "/fetchdata"
@inject HttpClient Http

// ... markup omitted for brevity

@functions {
  WeatherForecast[] forecasts;

  protected override async Task OnInitAsync()
  {
    forecasts = await Http.GetJsonAsync<WeatherForecast[]>("sample-data/weather.json");
  }

  // ...
}

Displaying the WeatherForecast data is done by iterating over the forecasts collection and binding the values to an HTML table:

@if (forecasts == null)
{
  <p><em>Loading...</em></p>
}
else
{
  <table class="table">
    <thead>...</thead>
    <tbody>
      @foreach (var forecast in forecasts)
      {
        <tr>
          <td>@forecast.Date.ToShortDateString()</td>
          <td>@forecast.TemperatureC</td>
          <td>@forecast.TemperatureF</td>
          <td>@forecast.Summary</td>
        </tr>
      }
    </tbody>
  </table>
}

No server is used or needed for these basic examples. If we plan to develop our application with hosting and web services then the Full-Stack or Server-Side templates may be a better starting point.

Blazor Full-Stack

The Blazor Full-Stack template encompasses the same project structure as the Client-Side template with a few additions. Just like the Client-Side template there is no HTML rendered by the server and all files are delivered to the client as static files including .NET binaries. The difference however is added ASP.NET Core hosting and Web API and a Shared project for common application logic.

The template includes three projects: a Client-Side Blazor application Blazor.Client, an ASP.NET Core server application Blazor.Server, and a shared .NET Standard project for common application logic Blazor.Shared.

Blazor.Server

The server application is responsible for serving the application and providing web API endpionts for data. In Startup.cs we'll find the MimeType settings which configure the server to allow *.wasm and *.dll files to be served. In addition, compression is enabled to help reduce the size of binary files as the are transferred to the client. Compression is enabled through the AddResponseCompression middleware.

services.AddResponseCompression(options =>
{
  options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
  {
    MediaTypeNames.Application.Octet,
    WasmMediaTypeNames.Application.Wasm,
  });
});

The Startup process also is where the Blazor application middleware is initialized by app.UseBlazor<Client.Program>. This identifies the Blazor.Client application which is being served.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseResponseCompression();
  // ...
  app.UseBlazor<Client.Program>();
}

The application comes with a simple example of a Web API controller and action. In the SampleDataController, a WeatherForecasts action generates a random set of weather forecasts. In the Full-Stack template, the WeatherForecasts web API replaces the static weather.json file found in the Client-Side template.

public class SampleDataController : Controller
{
  // ...

  [HttpGet("[action]")]
  public IEnumerable<WeatherForecast> WeatherForecasts()
  {
    // ...
  }
}

Blazor.Client

Nearly all of the Client application is identical to that of the Client-Side template. However, in FetchData example differs slightly by requesting data from the WeatherForcasts web API endpoint in the GetJsonAsync method call.

@functions {
  WeatherForecast[] forecasts;

  protected override async Task OnInitAsync()
  {
    forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");
  }
}

Blazor.Shared

Since the project includes a server and client solution that both use .NET it's possible to share code between both applications. This is a scenario unique to Blazor since the client is running .NET client side instead of JavaScript. The example given in the project template utilizes the same WeatherForecast class on both the server and client application.

public class WeatherForecast
{
  public DateTime Date { get; set; }
  public int TemperatureC { get; set; }
  public string Summary { get; set; }
  public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

The WeatherForcast class is just a basic idea of shared code, however other shared application code may include: validation, converters, and business logic which is decoupled from system, IO, or web concepts. Expanding on this idea further a theoretical application may share libraries between other .NET frameworks such as: Xamarin, Windows Universal Platform (UWP), or other .NET based web applications.

No Ahead-of-Time Compilation (AOT)

In other .NET web technologies like ASP.NET MVC (and Core MVC), the Razor templates are rendered by the server and sent to the client as HTML. Some JavaScript frameworks like Angular and React share rendering responsibilities on both client and server in a process called ahead-of-time Compilation (AOT) or Isomorphic Rendering. Even though the Blazor client application is hosted on a .NET server, all views are rendered client-side in both the Client-Side and Full-Stack project templates. Currently, there are no AOT/Isomorphic Rendering options for Blazor, but a Server-Side Blazor app model does exist.

Blazor Server-Side (aka Razor Components)

On September 12, during DotNetConf Blazor Server-Side was announced as a new feature in ASP.NET Core 3.0 and will be known as ASP.NET Razor Components.

ASP.NET 3.0 Razor Components will be the first official (non-experimental) release of the Blazor framework.

The Blazor Server-Side project template takes a significantly different approach to how a Blazor application is delivered and interacts with the browser. When using the server-side configuration Blazor utilizes the browser as a "thin-client" by deploying a SignalR JavaScript application to the client. On the server, Blazor implements a SignalR hub communicating with the client via web sockets. In the server-side hosting model, Blazor is executed on the server from within an ASP.NET Core app. UI updates, event handling, and JavaScript calls are handled over the SignalR connection. In this configuration there is no need for WebAssembly and Blazor is executed on the ASP.NET Core runtime at the server. All UI updates are sent as diffs, bidirectionally as binary packets over web sockets. To the user, the application is indistinguishable from any other web application.

Despite the drastic differences in how Blazor operates server-side, the actual application model stays relatively the same. In the server-side project template there are a only few differences in example code provided by the template. The template includes two projects: a Server-Side Blazor application App, an ASP.NET Core server application Server which hosts the Blazor app.

App

The index.html is the client entry point to the application. When configured for server-side operation the JavaScript file, blazor.server.js replaces blazor.webassembly.js. blazor.server.js invokes the SignalR client and establishes communication with the Blazor server-side application.

<!-- wwwroot/index.html -->
<!DOCTYPE html>
<html>
<head>...</head>
<body>
  <app>Loading...</app>
  <script src="_framework/blazor.server.js"></script>
</body>
</html>

Because the entire application runs server side, in this project type the Fetch Data example utilizes data from a local service. The @inject directive in this example resolves an instance of WeatherForecastService in place of HttpClient as seen in the Full-Stack project template. The WeatherForecastService in the example is a simple class that generates random data, however in a real-world scenario the service could be an Entity Framework database context, repository, or other sources of data.

@page "/fetchdata"
@inject WeatherForecastService ForecastService

// ... markup omitted for brevity

@functions {
  WeatherForecast[] forecasts;

  protected override async Task OnInitAsync()
  {
    forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
  }

  // ...
}

The WeatherForecastService and other services are added to the dependency injection container in the ConfigureServices method found in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
  // Since Blazor is running on the server, we can use an application service
  // to read the forecast data.
  services.AddSingleton<WeatherForecastService>();
}

Server

The server project provided by the template is a simple ASP.NET Core host. In the Startup.cs of this project, the UseServerSideBlazor middleware is invoked and the Blazor application's startup is initialized.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseResponseCompression();

  // ...

  // Use component registrations and static files from the app project.
  app.UseServerSideBlazor<App.Startup>();
}

Pros and Cons

Since only a small amount of JavaScript is required to bootstrap the client and no .NET assemblies are transferred to the client the Server-Side Blazor application is efficient with network traffic. Even during operation network traffic is light because communication between the browser "thin-client" and the server is a small binary packet. However, because web sockets are used, the client and server must always be connected. This means that Blazor Server-Side apps cannot work in offline mode.

Conclusion

While Blazor is an extremely new framework still in its experimental phase it ships with several ways to get started. Each project type includes a similar set of examples with the Counter and Fetch Data components. The Fetch Data example varies from project to project to showcase specific features of that project type.

With the Client-Side, Full-Stack, and Server-Side project templates developers can choose the starting point that best fits their application's requirements. The Client-Side template focuses on running static files completely in the browser, while the Full-Stack template includes ASP.NET Core hosting and Web API. Using the Server-Side template utilizes the Blazor framework on the server and relies on SignalR in place of WebAssembly thus trading performance for a dependency on always being connected.

If you're excited about Blazor and are ready to begin experimenting too let us know in the comments below. What are your plans for Blazor?


Ed Charbeneau is a Developer Advocate for Telerik
About the Author

Ed Charbeneau

Ed Charbeneau is a web enthusiast, speaker, writer, design admirer, and Developer Advocate for Telerik. He has designed and developed web based applications for business, manufacturing, systems integration as well as customer facing websites. Ed enjoys geeking out to cool new tech, brainstorming about future technology, and admiring great design. Ed's latest projects can be found on GitHub.

Related Posts

Comments

Comments are disabled in preview mode.