.NET 5.0 Blazor Web Assembly TODO List simple app
Tags: blazor, csharp, spa, webassembly
Published: 2020-12-12 20:49:27

![Blazor](https://dev-to-uploads.s3.amazonaws.com/i/6h5euqjvcnzewvzs0e6c.png)
Not so long ago Microsoft released .NET 5.0 and with this release, their front-end framework Blazor is getting even better support for Web Assembly hosting solution.

In this article, we will try to write a TODO list SPA Web Assembly application using this framework. 

But before diving in let’s talk a little bit about what kind of benefits and downsides Web Assembly hosting solution carry with it.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hoi8eed3nubqsoxrefd6.png)
> WebAssembly (often shortened to Wasm) is an open standard that defines a portable binary code format for executable programs, and a corresponding textual assembly language, as well as interfaces for facilitating interactions between such programs and their host environment. — Wikipedia

To say simply it is an interface between compiled binary code (mostly C++ and Rust) and the environment where it executed — in our case web browser (JavaScript). All modern browsers support Wasm so you don’t need to worry about this part. 

### **The Blazor WebAssembly hosting model offers several benefits:**
- There’s no .NET server-side dependency. 
- The app is fully functioning after downloaded to the client.
- Client resources and capabilities are fully leveraged.
- Work is offloaded from the server to the client.
- An ASP.NET Core web server isn’t required to host the app. Serverless deployment scenarios are possible (for example, serving the app from a CDN).

### **However, there are some downsides to Blazor WebAssembly hosting:**
- The app is restricted to the capabilities of the browser.
- Capable client hardware and software (for example, WebAssembly support) are required.
- Download size is larger, and apps take longer to load.
- .NET runtime and tooling support are less mature. For example, limitations exist in .NET Standard support and debugging.

Even with all downsides listed above, this solution looks really promising, so let say no more and start with our app!

#### **But before building it we still need to install [.NET 5.0.100 SDK](https://dotnet.microsoft.com/download/dotnet/5.0)** 

We are not going to write everything from scratch but instead, we start from Blazor WASM template by running the next command:
```bash
dotnet new blazorwasm -o ToDoList
```

![CLI message after running dotnet new command](https://dev-to-uploads.s3.amazonaws.com/i/hhrg07zwc40cficn1cfd.png)

It will generate a `ToDoList` folder with the following project structure:

![Project structure](https://dev-to-uploads.s3.amazonaws.com/i/zx6utl0vs7yu0alonvqh.png)

Let’s quickly go over some pieces of it, but if you bootstrapped Blazor projects before it will look very familiar to you.

*Pages* folder – Contains `razor` files for pages (routable), while *Shared* holds all shared components used in Pages. *wwwroot* is a public folder that contains all static data such as `css` style files and `index.html`. As you can see template shipped with Bootstrap components library. Still, one minor version behind (*on the date of writing this article Bootstrap has version 4.4 while template shipped with version 4.3.1, Microsoft should update templates faster, really…*)

Also, you may notice `open-iconinc` which is an open-source sibling of [Iconic](https://useiconic.com/), the icons library. Kinda cool addition, but you always could switch to any other icon library, e.g. Bootstrap introduced their own icon library `bootstrap-icons`.

*Program.cs* – is the main entry point of the whole app. for now it contains only a few basic lines. Services can be configured with the `ConfigureServices` method on the host builder.

E.g:
```cs
builder.Services.AddSingleton<IMyDependency, MyDependency>();
```

Configuration can be supplied via the host `builder builder.Configuration`. This is the main difference between Blazor Server and WebAssembly is the type of builder. As you could see for WASM application it is `WebAssemblyHostBuilder`

![Program.cs](https://dev-to-uploads.s3.amazonaws.com/i/k5rjfy5t7urc2l0s2vlw.png)


RootComponents specifies the HTML tag ID where `App` will be rendered, in this case `<app>…</app>` tag:

![index.html](https://dev-to-uploads.s3.amazonaws.com/i/9f5sxk03f5goduhuyit2.png)

Another interesting line here is `<script>` tag that points to `blazor.webassembly.js` file. This JS file is responsible for:

- Downloading the .NET runtime, the app, and the app’s dependencies.
- Initializing the runtime to run the app.

*App.razor* — The root component of the app that sets up client-side routing using the [Router](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.components.routing.router?view=aspnetcore-5.0) component. The `Router` component intercepts browser navigation and renders the page that matches the requested address.

![App.razor](https://dev-to-uploads.s3.amazonaws.com/i/vddmajrar2564j84mpv0.png)


This structure of components and their name styles reminds some other popular frameworks, such as VueJS.

*_Imports.razor* — Includes common Razor directives to include in the app’s components (.razor), such as `@using` directives for namespaces.

> NOTE: You could run the app by pressing F5 in VS Code. Alternatively to run it from CLI use `dotnet run command`. The app will be served at http://localhost:5000.

![Served template app](https://dev-to-uploads.s3.amazonaws.com/i/4o1u0olxs9sk7v34lv5n.png)


**But finally, let get to our app… For real this time!**

Let's add a new page file named *Todo.razor* to the app in the Pages folder. Notice `@page "/todo"` binds this page to the new route.

![Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/dlfgbj5litncjydatde4.png)

And update the navigation bar inside Shared/NavMenu.razor:

![Shared/NavMenu.](https://dev-to-uploads.s3.amazonaws.com/i/3o5446zw7hlzne5glpax.png)

Let's run the app with `dotnet watch run` command and we should see our link to TODO list on the NavBar that will bring us to our new page.
> NOTE. `dotnet watch run` will track the changes in the project files and refresh the browser. Similar to the live server. So you don't need to run it every time.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0tbbsn02h3s5c13vzqqu.png)

Ok. The next step is to introduce `TodoItem` model. Let's create a Model folder where we create TodoItem.cs file with next class:

![TodoOtem.cs](https://dev-to-uploads.s3.amazonaws.com/i/akdinbu9s59ndsg54caz.png)

Now when we have a model let use it inside Todo component. Go back to Pages/Todo.razor and add `@code` section at the bottom of the file. This section holds all component business logic. You could think about this section as a nested Class within the Component.

We will add a private field of `List<TodoItem>` there:

![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/0nmu399p4ihkz4ng0ekw.png)


Let's use this list to render TodoItems into UI. We are going to use an unordered list tag <ul> for that. Just use C# `foreach` to loop over the items.


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/hftjvynps0dwfdc19q0o.png)


As you may notice the `@` symbol is used for UI logic code insertions. Similar to [mustache](https://mustache.github.io/) syntax used in many popular Frontend frameworks.

Alright looks like we missing an input to actually add data to `todos` list. Go add it:


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/j28f03x94tu0ql5ix53g.png)


Now our ToDo list looks way more attractive!


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uyvq3uzdxze6c08ijdvg.png)


But it is not functional =( Let’s go fix it!. First we need to hook up `@onclick` handler to the button. For that create a private method within `@code` section and add `@onlcick` attribute so it will look like this:


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/9ppwlv4qix0hrthit5dx.png)


Ok, but we missing a data binding between `<input>` tag for Todo Title and component class. Let's introduce another `string` field and bind it to the `<input>` tag with `@bind` attribute:


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/84d1b8nfbi79j47ck59v.png)


And some spicy logic to the `AddTodo` method.


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/e9mqd3y4je478qv5zrw5.png)

Let’s test what we have so far. Because we using `dotnet watch run` the app already reloaded in the browser and we could try adding some “todos”.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/4f0rorun84tnob564lno.png)


It works! …. But looks boring… We will drop some extra functionality to gasp Blazor skills. Add UI tags and bind them to the model so we could edit “todos” title and status, but also count of undone tasks:


![Pages/Todo.razor](https://dev-to-uploads.s3.amazonaws.com/i/jfcuhblunxip4foijjt0.png)


Let see what we have this time?


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6vtm9jo842whw3p1lj84.png)


Delightful! Try changing values and see how reactivity works with model binding in Balzor. As you may notice when you change the title in the input, it reflects only when you unfocus the input element. This is the default behavior of Blazor `@bind` attribute. It triggers on `<input>` [“onchange”](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onchange) event:


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6vtm9jo842whw3p1lj84.png)


But of course, this behavior could be changed.


And that is it. We build or SPA ToDo list using Web Assembly with Blazor framework. To stop serving the app press `Ctrl + C.`


### Conclusion.

I really like how Blazor framework evolves and becomes more and more attractive, but like all other frameworks, it has its pros and cons. I like how easy it is to implement routing and model binding. Another benefit I like is a strong typed C# with and .NET 5.0 support that brings a lot of new features to the table.

It really helps C# developers who like to develop some frontend but doesn’t really want to dive into JavaScript nightmare =).

As for WebAssembly: yes it works fast but only when it's loaded. As you could see from Lighthouse report below, we build a pretty small app but it already has a size of around 9mb. So if your Web App is supposed to be more fast and lightweight from a user perspective, I will suggest you to avoid WASM.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1ymbln0zf2826j6k6ju2.png)


But if you build an online tool (e.g. photo editor or smth heavyweight and static) that loads once and performance very very good and fast — then WASM is a solution for you!

Source code could be found here: https://github.com/godszerg86/BalozorWASM_ToDO

In the next article, we will try to host a .NET 5.0 WASM application using Docker image locally on your machine.