Explore Blazor WebAssembly - use custom style, call external WebAPI, employ JavaScript interoperability

2 April 2020

Motivation

Blazor is a framework from Microsoft® for making web applications with .NET. In very short Blazor is C# for web browsers. There are two types of Blazor, Blazor WebAssembly and Blazor Server. This article is about Blazor WebAssembly. Notice that during the writing of this article, Blazor WebAssembly is still in preview. The term WebAssembly refers to a binary instruction format for stack-based virtual machine. In short it makes C/C++, Rust, C#* run in a web browser. It is designed to run alongside JavaScript. WebAssembly is an open web standard and it is supported in (most) web browsers. Those browsers who support it, all major browsers, supports it without plugins.

This article will demo the usage of Blazor WebAssembly and how to create simple web application with it. The article consists of three parts. In part one we are going to remove the default css framework and use other css framework, w3.css. Not because the default css is bad, it is more like to make styling simpler and show how easy is to change it.

In part two our web application will display dummy data from an external source, in this particular case an IBM Cloudant database. IBM Cloud allows users to develop for free, to build for free on IBM Cloud. No credit card is required for creating the account, as opposed to other providers, which require credit card even for free accounts. I guess this will allow wider audience to follow the article. The performance of free account is same as the paid one. Of course, the free account comes with restrictions – one of them is the cap of number of available calls to the cloud DB. For a production application you will need a paid account with a plan tuned to your needs.

In part three our demo web application will use together C# and JavaScript, technically known as JavaScript interoperability. It will be working with Airbnb® Lottie animation library. Grace to Lottie, our web application will display exciting svg animations. Lottie animations are usually done with a paid product, called Adobe® After Effects. We are going to use few already created animations, released by their authors for free.

Table of contents

What you will be able to make if you follow the entire article
Prerequisites to follow this article and make the described solution
Part One - Get Started
Part two - working with WebAPIs - calling IBM Cloudant, POST and GET, and few words about _id
Part three and final - JavaScript interoperability

What you will be able to make if you follow the entire article

Entire solution is created from scratch. It will require some typing and some work. If there is a place, where you give up reading it and move to another reading, then this one is the best. This article will not explain the code line by line, you need to read the code itself and figure it out. Of course, if there are questions, I will try to answer them to my best knowledge. In animated gif below you can see the finished web application and its usage. Credits to artist who made his Lottie animations available for free, you can find a link below in the article, when the part for using Lottie animations with JavaScript interoperability is explained in details. And of course, thanks to all who made their tools and systems available for free and this way allow people to create freely. Not only the tools mentioned in the prerequisites, but also Libre Office which provides the editor for typing the article during the creation, Screen to Gif for providing the tool for making the animated gif and many more.

Prerequisites to follow this article and make the described solution

This solution was created in spring of 2020 (amidst the Corona Covid-19 times), so current versions, at this time, of all products and corresponding frameworks, NuGet or NPM packages were used. For the .NET solution, the following IDE was used:

You need to install Blazor WebAssembly template. In order to have it, you will need the .NET Core 3.1 release as well. I have used the SDK release.

An IBM Cloud account. You can create developer account for free, no credit card required, on IBM Cloud and use lite plan services.

the following clide side JavaScript framework:

and the following CSS framework

Optional - for making simple local WebAPI, in order to be called by our Blazor web application

"Oxanium" font was used as default font.

Part One - Get Started

In this part we are going to create the Blazor WebAssembly solution. If you don’t have .NET Core 3.1. SDK, then you should follow the instructions provided by Microsoft and install it. You can use the certutil tool, installed with Windows, to verify the sha512 hash. Or some other tool.

Then, we continue with main stuffs for this part.

A few moments later our solution is ready. We select Debug -> Start Debugging or press F5 or click on the debug button in Visual Studio toolbar. If all is good, the default Blazor template appears in our browser of choice. In part one we are going to use Brave browser. We click on Fetch data and on Counter and test them, just to see everything is working. Pay attention that even that we use Debug, it is not actually (yet) possible to debug the C# in blazor @code part. Later in this article we are going to use Start without Debugging. It is kind of personal choice at the end.

Changing the css framework and removal of some stuffs we are not going to use

Now comes the fun part, where we delete some stuffs

It might be good idea to remove unused usings for every C# file, which you are going to use.

Making the new layout

Then we are going to change the main markup file, index.html, and to tune up the navigation, so it works after changes we have made so far.

At this point we run again the application. Thsi is how it looks now:

We are almost ready with the first part. It remains to add two pages in Pages folder, one for live demo and other for working and to update the NavMenu, so that we are able to navigate those two pages.

Part two - working with WebAPIs - calling IBM Cloudant, POST and GET, and few words about _id

This part assumes successful completion of part one or a working application similar to it. A common feature in a web application is making calls to remote APIs via the http protocol. At this point many other tutorials assume that the remote API is existing or they suggest usage of an existing demo API. In this article however, we do everything ourselves. This part of the article is again divided on two - the first, an optional part, where we create local simple service via node.js and express and we pretend it is our web API, and second part, which is going to be needed further in the article, where we call IBM Cloudant database. We are going to demonstrate how to set up the database and how to use it for doing basic stuffs in our Blazor WebAssembly web application.

Optional - Making local node.js hosted server

The default Blazor WebAssembly template comes with a server project and a demo controller, as well as demo class in Shared project. The calling of those is straightforward, Visual Studio even provides you with default implementation of C# methods for making calls via four main HTTP methods, GET, POST, PUT, DELETE, to REST web api, via its scaffolding option. When we run the default template we see that this is working just fine. The Server and Client in this case both share the same domain, localhost:44312 in my particular case. Let’s explore what will happen when we call other service, hosted on another domain.

I have created a folder D:\devdemos\BlazorFirstSteps\nodejsdemo. We open a Node.js command prompt and we navigate to our working folder. If you create it in different location, you should navigate accordingly. We type

npm install express
. It confirms that the installation is OK and warns about few things. We can create the REST, only the GET part actually, without express, but I guess it is little bit easier the way I present it here.

Then, we open Visual Studio Code, then we open the folder we just created. We create a new file called demodata.json. The content of the file is as follows:

Now we create a server.js. Bear in mind that we are going to slighly chage it few steps below, so that here is the initial version. We are going to run it via our node.js command prompt. You can run it as well with Windows® PowerShell. Visual Studio Code support terminal integration with PowerShell, so it is possible to run commands inside editor as well, like this:

In this tutorial we will keep the things simple and use the command prompt. So, we type

node server.js
in our command prompt and get the server running.

Then, we navigate to localhost:3030. We can see the demo.json content, which we created few steps earlier.

We go back to Visual Studio solution and open working.razor. We are going to make a GET call towards localhost:3030. We are going to use HttpClient, provided by Blazor. The code for Working.razor for this part is as follows:

and now we run our Blazor WebAssembly web application (for part two I have changed the browser to Microsoft Edge Beta, which again Chromium based), and to to Working. Then, we click on the button. Nothing happens, not even a message with response status string, different than OK, is shown.

Nothing is shown, because the browser itself has blocked the call. Let's open the developer console tab of our browser and see the error there. Main thing is the following: Access to fetch at 'http://localhost:3030/' from origin 'https://localhost:44312' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. Any Chromium based browser will display the same error. Mozilla's Gecko, (still) used in Firefox, will describe the error as: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 'http://localhost:3030/'. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

So in short our browser asked the server about CORS and did not liked what server told it. And because of that answer, the browser blocked the call. So, while our Visual Studio solution is running, we go back to node.js command prompt and stop the local server. Then, we change the server.js by adding few lines about CORS. Here is the final look:

and then we start the node.js server again. During our small manipulation our Blazor web application was still running, we did not switched it off. Let's go back to our browser and click the button again.

Good work! We get our demo data shown. Data is the same, the type I have made when making the json is here as well :) And now, let's move forward

Working with IBM Cloudant database and using it with our Blazor WebAssembly web application

You will need an account for IBM Cloud in order to follow, as stated in prerequisites. As of the time of writting this article, you can create a developer account for free, no credit card is required, as opposed to some other major providers. I am not going to explain steps in details here, because the IBM Cloud is a commercial site, owned by IBM, and they can change the way it is working according their needs, meaning any detailed description can be made obsolete.

IBM Cloudant

IBM Cloudant is a NoSQL cloud database, provided by IBM. When you log in into IBM Cloud and go to Catalog and then select Databases, you will see something like this, depending on your plan. There was filter for Lite plan selected, when the screenshot was made. So, you can follow the instructions and create a Cloudant database from here. There are some things to specify - locations, plans, etc., which you have to decide on your own.

After you create the Cloudant database, you can see an overview of it. You can manage it, manage Service Credentials, Plans and Connections.

You will need to create a service credentials. After you create those service credentials, you will be able to call your database using some of them. We are going to use Basic Authenticatioin, so we will need the username and the password.

Now, it is time to launch the Cloudant Dashboard. You might notice that you are redirected to a new url, having your (IBM Cloudant) username in it. We will refer to this part of site simply as Dashboard. From Dashboard, you select Databases and then you click on Create Database. I choose the name exploringblazor, as only lowercase characters are allowed, I have specified the options and I have confirmed with Create.

We need objects to store our data. So we have to design, or following Cloudant terms, to create a document. We click on Create Document or we click on the + sign in Design Documents and we select New Doc. A default document appears, having an autogenerated identification key (_id). In this document we are going to add few more fields. This is how the document looks just before we save it.

After we save it, we can look at it by going to All Documents and from there by selecting it. If we look at it in greater details, we can see that Cloudant had added a revision value (_rev). Using this revision Cloudant will track changes of document. There is a button called {} JSON. If you are looking at a document via the Dashboard editor and click on it, it will display the document, a json file, in a browser. Let's do that. We are going to need the url displayed in the browser. First part of this url is your username, then comes the database name, and then comes either a document id, or kind of query or something else :)

One final thing before we start populating fake data. We need to enable CORS for our newly created database. So from Dashboard we go to Account -> CORS. You might need to enable CORS. Later, we type the domain we need, in my case localhost:44312. By default unauthenticated connections are rejected by Cloudant, so we can put that localhost:port stuff. On later point I will remove it, probably once I am ready with making of this article.

Fill some dummy data using our web application

We have created a document using Dashboard UI and looked it. Usually databases contains millions, and even more, records or documents. We have to add more documents to our database, even for a simple demo. The good news is that we already have a working web application and we can use it for doing just this. How cool is that :)

When working with Cloudant and you POST data, usually in bulk, you must not provide a duplicate _id. So, if you have an class in your C# solution, you have to play with this _id property - it should not be serialized when json is made, but it should be deserialized, because you will need to identify a document if you want to track it, change it etc. At the moment of writting this article System.Text.Json does not suport that out of the box, you have to write custom code for it (contrary to Newtonsoft.Json for example). Anyway, in our sample this advanced usage will be ommited and we will simply not deal with _id and _rev in our Person class, the class we are going to create to handle the data in Cloudant.

I am going to generate some dummy data using simple class. Usage of faker/bogus data generators is a good thing, but in our case they will be slow and for our simple application there is no need for them now. More, I will create two enums, one for Status and one for Location, and the Person class.

If you are good with changes so far, it is time for running the web application and generate some fake data. We navigate to Working page and click on buttons to generate some number of records. Then we save them to Cloudant. We might do this several times. The process is split on separate generation and call to database in order to see how long each one of those processes is taking. For example, if you have a slow fake data generator, you should see it immediately when generating the data, not when you save it. In our case both processes should be quite fast. Here is the screenshot made just before I click the Save to DB button for first time.

and if everything goes well, we should see the created data in our Cloudant database. Those points are important, so play some time here, make sure everything is working, before moving forward.

I will create more records, to increase their number and work with slightly more data. Animated gif in the beggining was made while there were between 15-20 000 records in database. We are close to the end fof part two, not we have just to get data from Cloudant.

Execute a query against Cloudant database and show raw result in our web application

The other (bl/r)azor page, LiveDemo.razor, will serve this purpose, for sake of demonstration. We can show the usage of classical code-behind classes in Blazor.

Cool, we have the records from Cloudant. We are ready with part two! Good job. For now our application just show raw json, resulting from our call to cloud database. We are going to change the way it looks in next part and we are going to add some animations for making it look even cooler.

Part three and final - JavaScript interoperability

JavaScript is de facto the standard language for the web. It is the most popular language on github, it is term people ask most on stackoverflow (followed by java, C#, python and php). Blazor WebAssembly web applications can call (invoke is the precise term used in Blazor documentation) JavaScript functions and .NET methods can be called by JavaScript functions. This functionality is know as JavaScript interoperability, sometimes shorten to JS interop.

Basic example

JavaScript interoperability in Blazor is explained well in its documentation, blogs etc., so you can omit this part. We are going to demonstrate the idea, because in following slightly more complicated examples we need this working properly. In our C# we are going to use an interface called IJSRuntime. We are going to create a JavaScript function, which we will place in index.html, and we are going to call it in Home page or Index.razor. Here is the index.html after our changes:

and here is the index.razor

it remains to show the Home page, screenshot is made after I have clicked twenty times on the button :) For the third part of the article I am using Opera browser.

AirBnB Lottie animations

Lottie is the name of a library, that renders Adobe After Effects animations in real time, allowing applications to use animations as easily as they use static images. In HTML those animations are finally made into SVG animations, when final markup is made in client browser. We want this in our Blazor WebAssembly web application. We want instead of images to show animations. There are some web pages, where artists are generous enough and share some of their work. I am going to use few animations made by this artist - you can find his details on the following link, 'https://lottiefiles.com/Dahish'. It is from this site where I have downloaded the Lottie animations, used in the article, you can find plenty of Lottie animations there. Thanks for good work and for sharing. I am going to save two of those animations in D:\devdemos\BlazorFirstSteps\BlazorFirstSteps\Client\wwwroot\css\jsons and name them good.json and bad.json

Next, we are going to get the lottie.min.js from cdnjs site. I have used the following link: 'https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.6.7/lottie.min.js'. I have saved the file in D:\devdemos\BlazorFirstSteps\BlazorFirstSteps\Client\wwwroot\scripts under the name lottie.min.js. And later I have created a file called workLottie.js in the same folder. The content of this file are as follows (I have put an interesting commend in file itself, as a reminder mainly to myself about few troubles I experienced when playing with this):

Now we have to update Index.html and include references to both scripts, lottie.min.js and workLottie.js. If you did the optional part above, you have to remove the script method used there, if you want the final look of the file to be like this:

This will be the final version of index.html for the article. We continue by updating Index.razor, so that we load one of our animations and just check that everything is working fine so far. In order to display more animations at once, we are going to use Blazor components. This will be explained further in the following paragraphs. Back to Index.razor, Lottie animations, which in the final html, served at the client, will be svg animations, will be refered via ElementReference. Pay extra attention when working with external JavaScript libraries and you invoke them in Blazor, especially if they deal with rendering of elements. Here is the final version of Index.razor, the one seen in action in the animated gif as well:

and this is the Home page in browser

Formatting json data, received from Cloudant, as HTML and using Blazor components for displaying Lottie

We have come to final part of the article. First, we are going to make a special component, so that we display multiple Lottie animations on a page with (relative) ease. We will get then only the docs part from all json data, provided by Cloudant, other part being bookmark and warning if any, see part two of article for more details, and convert those documents to an array of Person objects. We will display properties of those Persons and we will format the HTML markup even further by using the Lottie animations.

Making of a Blazor component

Nothing fancy here, components are common for Blazor. We want to confine all the logic for working with Lottie in one C# file and just use this component as an image - that will say we say the name/path of the animation and we will expect corresponding animation to be shown in our page. We can use this component directly in our LiveDemo page. However, in it, in Live demo page we inted to display also multiple person and their fake generated data, so not only an animation for every person, but also names, location, and a number. Depending on the status, good or bad, we should display different animations, one for good and another for bad (and none for neutral, maybe just some strings to emphasis the difference). The markup for all this will not be trivial, so it will be good idea to contain it in a component as well. So, first we create a component for the animation only:

Now we will create a component, markup only, for displaying a single person. The markup will be quite simple, kind of card or a tile, some strings displayed in one column, some other strings displayed below, same thing in next column and then the animation. We will not get into big UI details, for example what will happen when some of those strings are too long :). Having tile, card or component like that will allows us easily to display multiple of it on one row in Live demo page.

Parsing documents from the received json to an array of objects

For easier work we will create class for parsing the raw json response, received from Cloudant. We will call it Cloudtant. It is quite simple and match the defined structure by the cloud database. When we put the data in Cloudant, we have used anonymous class, this is another approach too. Here is it, Cloudant.cs:

We are almost ready, only two things remain, the code-behind and markup for Live data page. In LiveData.cs we will have an array of Persons, which are going to be shown. We will fill this array by copying data from docs property of newly created Cloudant object. The rest is similar to code for LiveData.razor in part two.

The markup for LiveDemo.razor is pretty simple, especially as we put most of necessary stuffs in Person and Lottie components. We want the results shown in three columns, so we have a simple code for doing so. And here is it, the final markup for the article:

It was a long journey, but now we are ready and we can enjoy. We can run the demo Blazor WebAssembly web application and go to Live Demo, type something and see properly formatted results with animations displayed for those records, which meet certain conditions. Like this:

If you followed up to now, you will probably have similar applicatioin and you can run stuffs, close to those, demonstrated by the gif animation in the beginning of this article. Good job!

I hope you enjoyed the article

I have tried to create a good educational article, which emphasis on few important points. I have tried to fix all typos - code, functional or syntax, and I hope there are none, which are considerable. I hope someone find this article intersting.