WebAssembly Journey, [HANDS ON] real-time web application with Blazor + Kafka + SignalR

Sercan DUMANSIZ
10 min readJul 12, 2020

--

Let’s go back in time.

In 2006 Java compiled to JavaScript with Google Web Toolkit(GWT). In 2007 Phyton compiled to JavaScript with pyjamas.

For C/C++ programming languages, in November 2012 when the emscripten released these low-level programming languages also compiled to JavaScript.

If we mentioned C/C++ we need to talk about performance. Let’s have a look at how emscripten works?

https://emscripten.org/docs/introducing_emscripten/about_emscripten.html

I would like to draw your attention to the LLVM (Low Level Virtual Machine). If we summarize the magic of LLVM very simply. It optimizes the compiled code elegantly and the result of that compiled JavaScript (Subset of JavaScript) works faster than the normal JavaScript.

Who wants to go deeper about emscripten, I suggest you search about Alon Zakai. I’ll share some of his presentations at the end of the article. You might wonder how the Subset of JavaScript works faster than normal JavaScript, take a look at Alon Zakai’s presentation.

The result of these researches shows up as asm.js on 21st March 2013. asm.js placed on Firefox as an optimization module.

There is an important point about asm.js that we need to know, asm.js provides us just a two times slower performance than the native code (C/C++).

We shouldn't forget the name of Luke Wagner. You can reach asm.js features in his blog that he wrote in 2013.

Even asm.js has increased the performance of the web, there were still some concerns about it. Because when the application size grows the asm.js were struggling with performance problems. So Luke Wagner created the WebAssembly Community Group in 2015 to solve these performance problems and get a better experience than asm.js.

After two months later Microsoft announced that they are working with WebAssembly Community Group.

In February 2017 official logo released and after a month later Firefox became the first browser that supports WebAssembly.

From that day forth JavaScript is not the only language supported by browsers. But that doesn’t mean WebAssembly gonna replace with JavaScript although some of the areas which need more performance on will replace with WebAssembly. Because one of the goals for the WebAssmebly is solving the performance problems that runs on JavaScript.

I really wonder about your opinions about this. You can start an Q&A or just write something to create a discussion. 💬

Today WebAssembly supported by the four popular web browsers. If we understood the WebAssembly journey and noticed how early Microsoft joined the WebAssembly Community Group. We can continue with Blazor.

Blazor

Blazor offers two different solutions as Server Side and Client Side.

Blazor Server Side

Blazor Server runs .NET code on the server and interacts with the Document Object Model on the client over a SignalR connection.

In Blazor Server Side Hosting Model, all of our code runs on the server. Server needs to communicate with DOM(Document Object Model)to update the application user interface and it uses SignalR for that communication. SignalR opens a two-way connection between DOM and server and this connection helps to communicate server and browser.

Blazor Client Side

Blazor WebAssembly runs .NET code in the browser with WebAssembly.

In Blazor Client Side Hosting Model, all of our code works on web browsers. Thanks to WebAssembly our C# code can run on the browser.

Let’s see what is happening in the background.

In Blazor WebAssembly lifecycle, we see that JavaScript is still there. Blazor needs JavaScript to handle communication between WebAssembly and DOM.
WebAssembly calls Javascript interop to communicate with DOM as a result of that, we can call .NET functions from JavaScript and also call JavaScript functions from .NET. Our application loads by the web browser so we need to think what is the size of the application. Blazor WebAssembly 3.2.0 has Brotli compression format so we expect that our released application will be about 1.5MB. It’s a trade-off that we need to decide.

Blazor Server Side vs Blazor Client Side

Blazor Server Side Hosting Model needs an open connection between server and browser. Therefore our Blazor application can’t run offline and also our application’s performance depends on network quality and speed.

Blazor Client Side Hosting Model sends all of the application code to browser so that takes time to load by the browser. I think it’s going to be a get smaller with better compression algorithms. So the start of our application would be much slower than server-side but after our application is loaded by browser this application can run offline.

[HANDS ON] real-time web application with Blazor + Kafka + SignalR

When we look at our application architecture, first we have Paranoid Moons which are our worker services. These worker services collect Tweets that contain a given keyword from Twitter Streaming API. When the worker gets tweet it produces a message for Kafka topic which name is “twitter” topic.

Paranoia Consumers, consume messages from Kafka topic, and HTTP POST that message to Paranoid API which is inside Paranoid Planet. Paranoid API gets the request then inserts that data to MongoDB and then broadcasts data from SignalR Hub. Paranoid Presentation is our Blazor WebAssembly application which connects to SignalR Hub and consumes real-time data from SignalR connection and shows that data on Razor Pages.

If you have any question about this software architecture or have suggestion. Please write a comment that we can discuss.

[HANDS ON]

Let’s start with our worker service.

Inside Paranoid.Twitter.Moon directory,

dotnet new worker

running that command to create worker service. This worker service consumes tweets from Twitter Streaming API and then produces these tweets to Kafka topic.

We’re going to use docker-compose to create a Kafka Broker locally. It’ll also create a 1 replica — 1 partition Kafka topic which name is ‘twitter’.

docker-compose up -d

If you want to get more information about producers and consumers, you can use this documentation.

If you have any problem while implementing the producers and consumers you can write as comment. I’ll also share the source code soon so you can check it out from GitHub. For now you can follow me on GitHub for more information. Also you can ask or just write to me from Twitter.

Let’s continue with our Consumer application which is going to consume messages from Kafka topic.

Inside Paranoid.Consumer directory,

dotnet new console

running that command to create a consumer application.

Now we have our worker service which is consuming Twitter Streaming API and also produces a message to Kafka Topic. We also have a consumer to consume that data from Kafka Topic.

So let’s test these scenarios with write messages to console. I’m going to use “science” as a keyword. So we are going to see the tweets which contain ‘science’.

Yay! We completed the first part :)

Let’s continue with Paranoid Planet.

First of all, we’ll POST HTTP request instead of writing data to console. So we need to create an API project to answer the request.

Inside Paranoid.Planet.API directory,

dotnet new webapi

running that command to create a Web API project.

Let’s look at our POST end-point.

So the main job of this method is, first get the request and then insert data into MongoDB if the data successfully inserted then broadcast that data to given SignalR Hub.

We have a class which is ParanoiaHub this class inherits a Hub class from SignalR also uses IParanoiaHub as an interface.

We are going to create a ClassLibrary for the IParanoiaHub interface because we also use that interface in our Blazor project.

Inside Paranoid.Planet.Hub.Interfaces directory,

dotnet new classlib

running that command to create a ClassLibrary.

public interface IParanoiaHub
{
Task SpreadAsync(string content);
}
// Paranoid.Planet.API startup.csapp.UseEndpoints(endpoints => 
{
endpoints.MapHub<ParanoiaHub>(“/hubs/paranoia”);
endpoints.MapControllers();
});

In our Paranoid.Planet.API project we mapped SignalR Hub address to /hubs/paranoia so we also give that as a string in our Paranoid.Planet.Hub.Interfaces project’s ConfigurationSettings class.

As a result of these codes, we have end-point to answer the POST request and then we have a SignalR Hub to broadcast that request to Hub.

So we can start our Blazor WebAssembly project.

Inside Paranoid.UI directory,

dotnet new blazorwasm --hosted --pwa

running that command to create a Blazor Client Side Hosting Model project.

Because we added — hosted in our command we are going to serve our Blazor WebAssembly application on ASP.NET Core and we also have — pwa to support Progressive Web Application. (***hosted, this doesn’t mean Blazor Server Side Hosting Model***)

That command creates a project structure like above.

So if summarize what these folders have inside;

Inside Shared Project we’ll have the common objects that we are going to use on our Client project and Server project together. For example, we can put our model classes inside the shared project.

For about Server Project, we can think that as our back-end. We can put our business or maybe we can handle Authorization and Authentication implementations on this project.

So our Client project is a Blazor WebAssembly project that is fully running on the browser.

So we can think this project structure is like a popular SPA framework (Angular, Vue, etc.) As a result of that who is more familiar with the .NET ecosystem and knows C# can write an application to client-side and server-side together.

(***hosted, this doesn’t mean Blazor Server Side Hosting Model***)

Blazor WebAssembly, Chrome Browser Console

This is important that we should understand clearly. Our application is running fully on web browser. Our C# code loads by the web browser.

We’ll continue with our Client project.

We got a project Paranoid.Planet.Hub.Interfaces that we created earlier which contains IParanoiaHub and ConnectionSettings class.

We are adding this project to our Client project as a reference, and also adding SingnalR package.

dotnet add reference ../../Paranoid.Planet.Hub.Interfaces/Paranoid.Planet.Hub.Interfaces.csprojdotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.5

After that, we are implementing the SignalR Hub connection inside Index.razor page like below.

As you can see, we are just using .NET runtime and .NET libraries with C# programming language for client-side development on the web.

Let’s run project sequentially,

1- Paranoid.Twitter.Moon ( will use ‘corona’ as a keyword)
2- Paranoid.Consumer
3- Paranoid.Planet.API
4- Paranoid.Planet.UI

real-time Tweets that contain corona as a keyword.

[HANDS OFF]

https://stackoverflow.blog/2020/02/26/whats-behind-the-hype-about-blazor/

It’s possible to create different types of client projects with Blazor.
When will .NET 5 release Blazor will become more mature. In this article, I wanted to show you how WebAssembly works and also want to write an application from a .NET ecosystem perspective.

The Future of Blazor on the Client — https://youtu.be/qF6ixMjCzHA

If we look at Blazor’s future, it has also the same mindset with .NET 5. One framework for different types of applications and using C#’s power on client-side. If you are curious about the .NET 5 journey you can read my article about that journey.

My vision about the future of web development, we’ll use WebAssembly more because my experience shows me that when there is a goal and care about performance thins programming language, framework, tool, etc. win a seat in the industry. If we look at some of the WebbAssembly applications, I believe these applications and others that will develop with WebAssembly’s perspective will change our perspective to the web.

As a software engineer who is in the .NET ecosystem, I started with Blazor to understand WebAssembly. I advise you all who have experience with .NET, you can use your C# programming language skills to develop client-side and server-side applications together. If you want to use another language to understand WebAssmebly I suggest that you use Rust which will be also the topic of my next articles.

References

--

--

Sercan DUMANSIZ
Sercan DUMANSIZ

No responses yet

Write a response