Blazor is quite a new technology.
It has been shipped with the recent .NET Core 3.0, but was available earlier, in preview versions. Blazor enables developers to write web UIs using C# instead of JavaScript with the help of Razor markup syntax.
This means that we can use just one language across the whole web stack, like JavaScript in MERN or MEAN, to build business logic, as well as dynamic functionalities on the client-side. Apart from being a web-oriented framework, Microsoft plans on rolling out support for desktop and mobile platforms.
Sounds cool, doesn’t it? Now, let’s see it in action!
Blazor hosting models
Before jumping into coding, there is one important thing to consider – the hosting model. Currently, there are two available:
- Blazor WebAssembly
- and Blazor Server.
The latter might be for production use; however, Blazor WebAssembly is still in its preview edition.
Blazor WebAssembly
Blazor WebAssembly runs a client application directly in the browser. While requesting it from the server, .NET runtime environment is downloaded and initialised along with the application. This makes for longer loading time, but eventually the app is fully-functioning, locally, and without any .NET server-side dependency.
Blazor Server
With this model, the client application acts as a thin client. It connects to the server over the SignalR endpoint, and updates accordingly with incoming messages. Most of the heavy lifting moves server-side, which involves maintaining the client state and computing UI diff.
For this article, we will stick to the Blazor Server because it is easier to debug and generally requires less hustle.
Learning by example
To explore Blazor functionalities, I have built a tiny social network app. Source code is publicly available on GitHub along with the list of implemented features.
The project stands by the graceful name ‘Croaker’, and it enables users to share their thoughts in the form of short messages, labelled with hashtags.
Creating components
If you have some background in React or Angular, you will find it fairly easy to use Blazor. Components (reusable units of UI elements with dynamic functionalities attached to them), for instance, are one of the similarities.
They typically contain declarative UI code along with the implementation of component members in one file. They can split into separate files, but this approach is not recommended.
In the example below, you can see the implementation of the Croak component – an interactive card containing short messages with additional information such as the author name, or likes’ count.
For the sake of simplicity, styling has been omitted, with complete source code available on GitHub.
1 2 3 4 5 6 7 8 9 10 11
@using edu_croaker.Data.Dtos @using edu_croaker.Services @inject CroakService CroakSrv @namespace Components <Croak AuthorName="@CroakData?.AuthorName" Content="@CroakData?.Content" Hashtags="@CroakData?.Hashtags" LikesCount="@CroakData?.LikesCount" IsLiked="@IsLiked" OnLikeClick="@LikeAsync" OnRemoveClick="@Remove"/> @code { [Parameter] public CroakDto CroakData { get; set; } protected bool IsLiked { get; set; } protected async Task LikeAsync() { var likeDto = await CreateLikeDtoAsync(); if (!IsLiked) { if (CroakSrv.LikeCroak(likeDto)) CroakData.LikesCount++; } else { if (CroakSrv.UnlikeCroak(likeDto) CroakData.LikesCount--; } IsLiked = CroakSrv.IsLiked(likeDto); } protected void Remove() { /* ... */ } protected async Task<LikeDto> CreateLikeDtoAsync() { /* ... */ } /* ... */ }
In our UI code, we can see some embedded C# instructions like @foreach, @if or @onclick, this is Razor syntax. It is used for wiring up dynamic content to the static HTML. In a @code scope, we hold all the members that would go to a classic C# class. In this example, we define some component parameters. These are implemented as public class properties followed by the [Parameter] attribute.
Using components
We can easily use our components, just like any other standard HTML element.
1 2
{ "dotnet", "cs", "webdev" })" LikesCount="1" IsLiked="true" IsDeletable="true"/>
Since we know how to create a component, we would like to feed it with some real data. History has taught us that mixing up server interaction logic with data displays are typically a bad idea. To avoid it, we can apply a Container Pattern – Eduardo Vedes did an outstanding job explaining this concept.
To ensure a Croak component as stateless (it only displays data provided in parameters), we introduce the CroakContainer component. It provides data and takes responsibility for responding to the events which involve communication with the service layer.
1 2 3 4 5 6 7 8
@using edu_croaker.Data.Dtos @using edu_croaker.Services @inject CroakService CroakSrv @namespace Components @code { [Parameter] public CroakDto CroakData { get; set; } protected bool IsLiked { get; set; } protected async Task LikeAsync() { var likeDto = await CreateLikeDtoAsync(); if (!IsLiked) { if (CroakSrv.LikeCroak(likeDto)) CroakData.LikesCount++; } else { if (CroakSrv.UnlikeCroak(likeDto) CroakData.LikesCount--; } IsLiked = CroakSrv.IsLiked(likeDto); } protected void Remove() { /* ... */ } protected async Task CreateLikeDtoAsync() { /* ... */ } /* ... */ }
Razor provides fancy syntax for injecting services into our components. Croak container uses CroakService to call business logic related to liking and removing posts As you can see, we can reuse model and DTO classes directly in the client app, which makes it easier to maintain integrity and cohesion.
Razor rendering systems rely on the state of the UI. When a variable changes, all components dependent upon it re-render, according to the new state. In our example, this occurs in the LikeAsync method. Once a user presses the ‘Like’ button, we invoke appropriate service methods and change the UI state based on their response. Blazor computes visual differences and applies them selectively so that only certain components are updated.
Pages
At the top level, components are composed into pages. Each page has one or more routes specified. For instance, our Indexis a default page, that’s also accessible through byHashtag or byUser routes.
1 2 3 4
@page "/" @page "/byHashtag/{Hashtag}" @page "/byUser/{UserName}" @{/* UI components */} @code { [Parameter] public string Hashtag { get; set; } [Parameter] public string UserName { get; set; } /* other members */ }
Building a web app
Now, as you know these basics, you can start with building your first web application using Blazor. In our case, Croaker split into three layers:
- Core – services, models, business logic
- Infrastructure – repositories, database interaction
- Web – client application
Components and pages were placed separately into respective directories. Web project references Core and Infrastructure modules, as all services and dependency registration performs in its Startup class. As for third-party modules, LiteDB was used for storing data, with authentication duties gracefully handled by IdentityUI. Last but not least, Bootstrap made styling our components more convenient.
The image below shows the final output.
Final thoughts
To sum up, Blazor is paving the way towards a world of front end development. If you are familiar with .NET tech stack or any modern UI framework, it will be easy for you to get up and running with Blazor. Using C# for full-stack development brings a more unified experience in building web apps. This also means that certain parts of the backend codebase are shareable with client apps.
Due to being a new technology, Blazor is still missing some features, and sometimes you may end up writing custom workarounds. Fortunately the project is under active development, and new features emerge systematically. Microsoft has laid out its bright plans for future releases, so in my opinion, it is definitely worth giving it a try.
Explore .NET Application Development with SoftwareHut