Hosting a Containerized Client Side Blazor Application On Azure

Wael Kdouh
Dec 2 · 7 min read

Its not a secret by now that Blazor is taking the .Net Core world by storm. I won’t go into the details of what Blazor is or what the different hosting models are as its been widely discussed in the community. For a quick reference of Blazor overview as well as the different hosting models you can check the Microsoft docs located here and here respectively. In this post I will mainly focus on hosting a containerized client side Blazor application on Azure. I will use Azure DevOps to build a CI/CD pipeline which will deploy the Docker image that contains our Blazor application. I will also utilize Azure Container Registry (ACR) to store the Docker images. And finally I will use Azure App Service to run the Docker image which will serve our application.

Please keep in mind that at the time of writing this post client side Blazor was still in preview (version 3.1.100-preview3–014645). Thus, you will need to install the latest .Net Core Previews SDK which you can find here. Once you have the SDK installed you can either use Visual Studio or the dotnet CLI as discussed here.

Start by creating a a new Blazor application using Visual Studio 2019 (you can also use the dotnet CLI) as shown below. Notice that the “Enable Docker Support” checkbox is disabled with the client side option (aka WebAssembly App), so we will manually add the Dockerfile later on.

Note: I imagine this checkbox will be enabled once client side Blazor gets out of preview.

Creating a Client Side Blazor App Using Visual Studio 2019

The newly created project structure is shown in the image below. As you can see, Blazor is just a regular ASP.Net Core application. All the different artifacts that you have come to expect from an ASP.Net Core application are present here (Program.cs, Startup.cs, wwwroot, etc.).

Client Side Blazor App

If you run the application you will notice something unique here. Basically all the dlls, static files, as well as .Net runtime (Mono) are served down to the browser as shown in the image below. This is extremely important to understand as it highlights the fact that a client side Blazor application is constituted of artifacts that get served down to the browser and later executed in the browser and thus there is nothing executing on the server side. This is a typical behavior of Single Page Application (SPA) frameworks like Blazor.

Different Client Side Blazor Artifacts Served Down and Executed In the Browser

To understand how Blazor works at runtime, we need to understand the Blazor client side bootstrapping process. The bootstrapping happens in the main method in the program.cs file which loads the Startup class.

Bootstrapping a Blazor App Starts in the Program.cs File

If you look at the Configure method in the Startup class you can see the App component being associated with the app tag from index.html. A Blazor component uses a custom tag like <app>, and the Blazor runtime replaces the tag with the component’s markup, which is normal HTML recognized by the browser.

The Startup.cs Configure Method Associating the app Element to the App Component

Below is the index.html file which includes the <app> element. This is similar to the behavior of other SPA frameworks like Angular where you have the root component that bootstraps the whole application at runtime.


The most important thing to keep in mind here is that the whole bootstrapping process leads to loading the app component as the root component which is responsible for installing the router as shown below. The router is responsible for loading a Blazor component depending on the URI in the browser.

App Component Installs the Router

As you can see from the aforementioned bootstrapping process all the routing happens in the browser after the initial loading. Thus, all you really need is a server to serve the initial assets after which all the routing is handled in the browser. As a matter of fact you can use a Content Delivery Network (CDN) like Azure CDN to host your code as there is no server side interaction beyond the initial serving of the artifacts. In this post I will be using Nginx running inside a Linux container to demonstrate hosting using an Azure App Service, but having a web server is not a requirement for client side Blazor.

Add the following Dockerfile to your project. This is a multi-staged Dockerfile which builds the Blazor application in the first stage and then copies the published artifacts to the Nginx directory.

FROM AS build-env
COPY . ./
RUN dotnet publish -c Release -o output
FROM nginx:alpine
WORKDIR /var/www/web
COPY — from=build-env /app/output/DockerizedClientSideBlazor/dist .
COPY nginx.conf /etc/nginx/nginx.conf

In addition, add the following nginx.conf file to your project to ensure that Nginx properly serves our Blazor application:

events { }   http {      include mime.types;      types {         application/wasm wasm;       }     server {        listen 80;        index index.html;        location / {           root /var/www/web;           try_files $uri $uri/ /index.html =404;        }     }}

Go ahead and build the Docker image locally on your machine. We will later automate building the image using Azure DevOps. Build the image using the following command:

docker build -t dockerizedclientsideblazor .

After building the Docker image you can remotely connect to it to confirm that it includes the expected artifacts using the following command:

docker run -it — entrypoint /bin/sh dockerizedclientsideblazor

The following image shows the content of the Docker image. Notice the _framework folder which contains the dlls as well as the different static contents. This is the same folder that is referenced from within the index.html file in the Blazor project.

Blazor Artifacts Inside the Nginx Hosting Directory

We are now ready to build this image and push it to Azure Container Registry in order to later host the image using Azure Web Apps for Containers. I will use Azure DevOps to build CI/CD pipeline. The beauty of containers is that the heavy lifting happens within the image itself. Thus, our pipeline will simply contain a single task which builds and publishes our docker image. The following image shows the Azure DevOps pipeline:

Note: The pipeline assumes that you have created an Azure DevOps project as well as an ACR ahead of time.

Azure DevOps Pipeline For Building and Pushing the Docker Image To ACR

If you manage to successfully run your Azure DevOps build then you should expect to see the Docker image stored on your ACR as shown here:

Azure Container Registry (ACR) Hosting the Docker Images Resulting From the Build

We are now ready to pull the image hosted on ACR into our Azure App Service. Specifically, we will create a Web app for Containers which can host a Docker image.

Web App for Container Which Will Host Our Containerized Blazor Application

Head back to your Azure DevOps project and create a release pipeline which will pull the image from ACR and deploy it to the Azure App Service that we created above. Here is the release pipeline.

Azure DevOps Release Pipeline to Deploy the ACR Image to an Azure App Service

If the release pipeline executes successfully then you should see the following information under the Azure App Service “Container Settings” blade back on your Azure portal as shown here:

Azure App Service Container Settings Blade Showing Successful Deployment of the Docker Image

Now if you head to the “Overview” blade and browse the application, you should be able to load a client side Blazor application that is being served by an Nginx web server inside a container hosted on Azure App Service. As a matter of fact if you open the browser developer tools (aka F12 tools), you will notice that the server is Nginx and not Kestrel (which is the default ASP.Net core web server). This is shown in the image below.

Client Side Blazor Application Served by Nginx Inside a Docker Container

As you saw in this post we were able to demonstrate containerizing a client side Blazor application using different Azure services ranging from Azure DevOps for building a CI/CD pipeline, to Azure Container Registry for hosting a Docker image, and finally we used Azure App Service to host the Docker image.

Wael Kdouh

Written by

Premier Consultant @Microsoft. I am a Web Enthusiast. Oh and Public Speaking is kinda my thing. #Microsoft, #emp, #Msftemployee,

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade