Getting started with Blazor
Tags: blazor, webassembly, dotnet
Published: 2022-05-28 01:16:04

---
title: Getting started with Blazor
published: true
date: 2022-03-28 00:00:00 UTC
tags: blazor,webassembly,dotnet
canonical_url: https://insight-services-apac.github.io/2022/03/28/getting-started-with-blazor.html
---

Blazor is a [Single Page Application](https://en.wikipedia.org/wiki/Single-page_application) development framework. The name Blazor comes from the words Browser and [Razor](https://en.wikipedia.org/wiki/ASP.NET_Razor).   
Blazor either runs server-side or client-side. With the server-side model it executes on a server and sends the rendered HTML and CSS to the browser. In the Blazor Server Model UI events are sent back to the server using SignalR then the UI changes are sent to the client and merged into the DOM. Blazor client-side model runs in the browser by utilising [WebAssembly](https://blazor-university.com/overview/what-is-webassembly). It does not require any plugin installed on the browser. Since WebAssembly is a web standard, it is supported on all major browsers and devices. Code running in the browser executes in the same security sandbox as JavaScript frameworks.

### Why use Blazor

The first question you would ask straight away when you hear about Blazor is why Blazor? And why not use another JavaScript framework like React or Angular. This is not an easy question to answer. JavaScript frameworks have been there for a while and gained a lot of popularity and success. I’m not trying to convince you with Blazor over other UI frameworks here, but I’m going to list the features and capabilities that attract most people to Blazor and might be good reasons for you too to start using Blazor.

**.NET Experience**  
  
This might be the primary selling point of Blazor. If you are a .NET developer with no or little JavaScript experience Blazor allow you to start developing web applications without having to learn a new technology. You can use libraries or frameworks that you already use with your .NET projects as long as they are compatible with [.NET Standard](https://docs.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-1-0).

**WebAssembly**  
  
WebAssembly (abbreviated _Wasm_) is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications. In November 2017, Mozilla declared support in all major browsers after WebAssembly was enabled by default in Edge 16. The support includes mobile web browsers for iOS and Android.

JavaScript is a high-level language, flexible and expressive enough to write web applications and has a huge ecosystem that provides powerful frameworks, libraries, and other tools, whereas WebAssembly is a low-level assembly-like language with a compact binary format that runs in the browser with near-native performance.

Blazor supports JavaScript interoperability. Using Blazor does not mean “No JavaScript”. You can still call JavaScript functions from .NET apps and vice versa.

**Code Reusability**  
  
With Blazor you are using .NET throughout your different application layers. Developers in your team can easily work with backend or frontend. This means that you can reuse code between your backend and frontend, use your common libraries across application layers and share API models. Think about utilities like string formatters, DateTime helpers, cryptography and a lot more. You can now have one library that you can use across all different projects - backend or frontend.

**Server-side Rendering**  
  
One of the primary requirements that you would frequently be asked for when developing SEO friendly websites is server-side rendering. Server-side rendering is important when you build applications intended to be crawled by search engines as it allows bots to crawl your website contents without having to execute JavaScript code. By using Blazor, server-side rendering is included as standard.

### Blazor WebAssembly vs. Blazor Server

**Blazor WebAssembly**  
  
In Blazor WebAssembly (or the client-side hosting model) the application runs directly in the browser on WebAssembly. So, the compiled application code itself, dependencies and the .NET runtime are downloaded to the browser. This means that the application will need some time to download and load the application and dependencies assemblies at start-up. However, this means the app remains functional if the server goes offline.

![Blazor WebAssembly Hosting Model](https://insight-services-apac.github.io/assets/images/first-blazor-app/wasm-hosting-model.png)   
Reference: [ASP.NET Core Blazor hosting models](https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models)

**Blazor Server**  
  
In Blazor Server (or the server hosting model) the application is executed on the server from within an ASP.NET Core application. Between the client and the server, a SignalR connection is established. When an event occurs on the client such as a button click the information about the event is sent to the server over the SignalR connection. The server handles the event and the generated HTML. The entire HTML is not sent back again to the client, it’s only the diff that is sent to the client over the established SignalR connection. The browser then updates the UI.  
Because code run on the server, the initial load is much faster than Blazor WebAssembly. The application can take advantage of server capabilities such as .NET Core APIs which allows utilizing the existing tooling such as debugging. However, the main concern with using this model is the high latency as every user interaction will require a network hop and this means also that there is no offline support.

![Blazor Server Hosting Model](https://insight-services-apac.github.io/assets/images/first-blazor-app/server-hosting-model.png)  
Reference: [ASP.NET Core Blazor hosting models](https://docs.microsoft.com/en-us/aspnet/core/blazor/hosting-models)

### Create your first app

In this article, we’ll go through the steps of how to create and deploy a Blazor WebAssembly app. There are two types of Blazor WebAssembly apps, stand-alone and hosted models.

**Standalone** is suitable when you intend to deploy your app without an ASP .NET Core app to serve it, for example hosting the app on IIS server or Azure App Service (windows).

**Hosted** the app uses an ASP.NET Core server to host the client App which gives you the flexibility to host it in Azure App Service (Windows or Linux) and allow you to share code between client and server apps.

In this article, we’ll be using hosted Blazor WebAssembly.

**Create the project**  
  
Visual Studio Code

For the command line run the following:

`dotnet new blazorwasm --hosted -o FirstBlazorApp`

Visual Studio

From Visual Studio Choose Blazor WebAssembly App template and make sure ASP.NET Core hosted option is selected.

![VS Create Blazor App](https://insight-services-apac.github.io/assets/images/first-blazor-app/vs-create-blazor-app.png)

Now open the project in your favourite editor and you will get the following folder structure:

![Blazor Hosted Folder Structure](https://insight-services-apac.github.io/assets/images/first-blazor-app/blazor-hosted-structure.png)

You will have three projects created in your solutions.

- **Shared** a class library project referenced by both Client and Server and the purpose of this project is to include all the code shared between the client and server such as API models.
- **Client** the Blazor WASM project. It has all the code required to run your Blazor client App.
- **Server** an ASP.NET Core project. You can create your APIs in this project which will run in the same environment as your client app. This app also acts as a host server to run your client app. This is enabled in the `Program.cs` file by a simple line:  
`app.UseBlazorFrameworkFiles();`

### Run the project

To run the project:

- Go to Client folder (if you want to run the standalone client without the server) or Server folder (if you want to run both server and client).
- Run this command to start the app `dotnet run`
- From the browser navigate to [http://localhost:5173/](http://localhost:5173/)

### Walkthrough

Under Client folder we have the following:

- `_imports.razor` contains all the namespaces imported and used by the project.
- `App.razor` is the main component of the app. It has the `Router` component which loads all the pages inside the `RouteView` component. If the URL was not found the app displays the template in `NotFound` component.

```
<Router AppAssembly="@typeof(App).Assembly">
  <Found Context="routeData">
    <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    <FocusOnNavigate RouteData="@routeData" Selector="h1" />
  </Found>
  <NotFound>
    <PageTitle>Not found</PageTitle>
    <LayoutView Layout="@typeof(MainLayout)">
      <p role="alert">Sorry, there's nothing at this address.</p>
    </LayoutView>
  </NotFound>
</Router>

```

- `wwwroot` has the client-side assets and styles. In Blazor WebAssembly `index.html` is the main entry point to the application. You can add any CSS or JavaScript references to this page. You can also redesign how the loading page should look during the initial load.

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />
    <title>FirstBlazorApp</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="FirstBlazorApp.Client.styles.css" rel="stylesheet" />
  </head>

  <body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
      An unhandled error has occurred.
      <a href="" class="reload">Reload</a>
      <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
  </body>
</html>

```

- `Shared` Under Shared folder, you will find the `MainLayout.razor` and all other shared components. MainLayout has been set as the DefaultLayout in the `App.razor`.
- `Pages` Under pages, you will find the components which will be rendered inside the MainLayout. In the page component, there are three main pieces you need to understand: 
  - `@page` directive which defines the route Url for the current page
  - `PageTitle` overrides the application page title.
  - `@code block` allows you to write your code in the same file with the razor template.

```
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code { 
    private int currentCount = 0; 
    
    private void IncrementCount() 
    {
        currentCount++; 
    } 
}

```

### Code-behind

As you can see in the previous example both the HTML markup and the C# code exist in the same file, which makes it easy and simple to build components in Blazor. However, as the business grows and requirements get bigger and more complex, splitting the code into a Code-behind file might be a good idea to keep the code clean and easy to maintain.

Splitting Blazor’s component code into a separate file is easy as all `.razor` files become classes when the project is compiled. For example, the code inside the `Counter.razor` file gets extracted into a class called `Counter` when compiled.

To move the code inside a component into a separate class there are two methods to achieve that:

**Partial Class**  
  
To create a partial class for the Counter component, create a new class file and call it `Counter.razor.cs` then add the following code to it:

```
namespace FirstBlazorApp.Client.Pages;
public partial class CounterComponent
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

```

Now, you can remove the code block from `Counter.razor` and build the project and you’ll find that it builds successfully with no errors.

**Inheriting ComponentBase class**  
  
Instead of creating a partial class for your components, you can create a class that inherits from `ComponentBase` class. You can then remove the code block from the `.razor` file and use the `@inherits` directive to inherit from the class you have just created.  
Note that in this method you need to modify access modifiers from private to protected to be able to access them from the `.razor` file.

Because the class inherits from `ComponentBase`, another benefit you get is that you have access to the component’s lifecycle methods such as `OnInitializedAsync()`.

You can find more details about component lifecycle in the following article: [ASP.NET Core Razor component lifecycle](https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-6.0)

- _Counter.razor.cs_

```
using Microsoft.AspNetCore.Components;
namespace FirstBlazorApp.Client.Pages;
public class CounterComponent : ComponentBase
{
    protected int currentCount = 0;

    protected void IncrementCount()
    {
        currentCount++;
    }

    protected override Task OnInitializedAsync()
    {
        return base.OnInitializedAsync();
    }
}

```

- _Counter.razor_

```
@page "/counter"
@inherits CounterComponent

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

```

### Scoped styles

Blazor supports scoping CSS to Razor components, which can simplify CSS and avoid collisions with other components or libraries.

To enable CSS isolation is simple. Create a `.razor.css` file matching the name of the `.razor` component file in the same folder. For example, to create isolated CSS for the `Counter` component create a file called `Counter.razor.css` in the same folder as `Counter.razor` file.  
The styles defined in `Counter.razor.css` are only applied to the rendered HTML of the `Counter` component.

For more details about Blazor CSS isolation see the following article:  
[ASP.NET Core Blazor CSS isolation](https://docs.microsoft.com/en-us/aspnet/core/blazor/components/css-isolation?view=aspnetcore-6.0)

### Writing unit tests

In unit tests, only the Razor component (Razor/C#) is involved. External dependencies, such as services and JS interop, must be mocked.  
There’s no official Microsoft testing framework for Blazor, but Microsoft [recommends](https://docs.microsoft.com/en-us/aspnet/core/blazor/test?view=aspnetcore-6.0#test-components-with-bunit)using `bUnit` which provides a simple and easy way to unit test Razor components.

The good news is that `bUnit` works with common testing frameworks, such as `MSTest`, `NUnit`, and `xUnit` which makes bUnit tests feel like regular unit tests.

Let’s go through the steps of how to start writing unit tests with bUnit using xunit testing framework:

1. Create a xunit test project by running:  
`dotnet new xunit -o FirstBlazorAppTests`
2. Under FirstBlazorAppTests add reference to FirstBlazorApp project:  
`dotnet add reference ../Client/FirstBlazorApp.Client.csproj`
3. Add the following NuGet packages:  
`dotnet add package bunit.web`  
`dotnet add package bunit.xunit`
4. Now you can start writing unit tests as you would normally do with any .NET project

The following is an example of a test class for the `Counter` component:

```
using Bunit;
using Xunit;
using FirstBlazorApp.Client.Pages;

namespace FirstBlazorApp.Tests;

public class CounterComponentTests
{
    [Fact]
    public void CounterComponentTest()
    {
        // Arrange: Render the Counter component
        using var ctx = new TestContext();
        var cut = ctx.RenderComponent<Counter>();

        // Act: Find and click the <button> element
        cut.Find("button").Click();

        // Assert: Find the <p> element, then verify its content
        cut.Find("p").MarkupMatches(@"<p role=""status"">Current count: 1</p>");
    }
}

```

For more details about bUnit see the official bUnit documentation:  
[Testing Blazor components](https://bunit.dev/docs/getting-started/writing-tests.html?tabs=xunit)

### Deploy the Blazor app

In Blazor Server model a web server capable of hosting an ASP.NET Core app is required in order to run your Blazor app. However, in Blazor WebAssembly there are two deployment strategies:

1. **Standalone deployment**  
The app is hosted on a static web server where .NET is not used to serve the app. Any static file server can host the Blazor app.
2. **Hosted deployment**  
The app is served by an ASP.NET Core app that runs on a web server. As you can see in the previous example, we have two main Projects (Client and Server). The Client project produces the static files required to run the app whereas the Server project contains the ASP.NET Core app that acts as a small server to host the client app.

**Deploy to Azure App Service**  
  
You can publish and deploy the Blazor app directly from VS Code which is a convenient and efficient way to deploy Blazor apps during the development process. However, for production, you should always consider using Continuous Deployment to deploy your apps.

**_Deploy from VS Code_**

Let’s go through the steps for how to deploy FirstBlazorApp that we have just created to Azure App Service using VS Code.

1. Install Azure App Service extension and configure it: [Azure App Service VS Code Extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azureappservice).
2. Publish the app. When you deploy Blazor WASM to Azure App Service windows you can use both strategies (Standalone or Hosted), however, if you wish to host the app on Azure App Service Linux you won’t be able to use the Standalone strategy. 
  1. Standalone deployment (windows):  
 Publish the Client app to generate the deployment package:  
`dotnet publish Client -c Release -o ./publish`
  2. Hosted deployment (Windows or Linux):  
`dotnet publish Server -c Release -r linux-x64 -o ./publish`
3. Now right click on the publish folder that has been just created and select `Deploy to Web App…`

**_Deploy from Azure DevOps_**

Finally, we’ll go through the steps of how to configure Azure DevOps pipelines to build, test and deploy our FirstBlazorApp to Azure App Service. To do so:

1. First, push your code to a new repository.
2. From the Azure Portal create an Azure App Service and set the runtime stack to `.NET 6`.
3. Go to Azure DevOps and create a new pipeline.
4. Select your code repo and proceed to the Review step.
5. Go to Project `Settings > Service` connections and create a new service connection then select `Azure Resource Manager` type then choose `Service Principal (automatic)` and set scope level to subscription.
6. Click `Variables` and add the required variables 
  - `AzureServiceConnection` The name of the Service connection created in the previous step.
  - `ResourceGroup` The name of the resource group where your app service is created.
  - `WebAppName` The name of the App Service to deploy the app to.
7. Paste the following YAML then click `Save and Run`

```
trigger:
  - main

pool:
  vmImage: ubuntu-20.04

variables:
  buildConfiguration: "Release"
  dotNetVersion: "6.0.x"
  location: "australiaeast"
  dotNetFramework: "net6.0"
  webAppDir: "$(Build.SourcesDirectory)/Server"
  webAppTestDir: "$(Build.SourcesDirectory)/Tests"

steps:
  - task: UseDotNet@2
    displayName: Use .NET 6.0
    inputs:
      packageType: "sdk"
      version: "6.0.x"

  - script: dotnet build --runtime linux-x64 --configuration $(buildConfiguration)
    workingDirectory: "$(webAppDir)"
    displayName: "Building App..."

  - task: DotNetCoreCLI@2
    displayName: "Testing App..."
    inputs:
      command: test
      projects: "$(webAppTestDir)/*.csproj"
      arguments: "--configuration $(buildConfiguration)"
      publishTestResults: true

  - task: DotNetCoreCLI@2
    displayName: "Publishing App..."
    inputs:
      command: publish
      workingDirectory: "$(webAppDir)"
      publishWebProjects: false
      zipAfterPublish: True
      arguments: "--runtime linux-x64 --configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)"

  - task: AzureRmWebAppDeployment@4
    displayName: "Azure App Service Deploy"
    inputs:
      azureSubscription: "$(AzureServiceConnection)"
      ResourceGroupName: "$(ResourceGroup)"
      appType: webAppLinux
      WebAppName: "$(WebAppName)"
      Package: "$(Build.ArtifactStagingDirectory)/**/*.zip"

```

### References

1. [ASP.NET Core Blazor](https://docs.microsoft.com/en-us/aspnet/core/blazor/?view=aspnetcore-6.0).
2. [bUnit](https://bunit.dev).
3. [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly).
4. [Single-page application](https://en.wikipedia.org/wiki/Single-page_application).
5. [ASP.NET Razor](https://en.wikipedia.org/wiki/ASP.NET_Razor).
6. [Host and deploy ASP.NET Core Blazor WebAssembly](https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/webassembly?view=aspnetcore-6.0).