Blazor: C# in the browser

Blazor is an exciting new way for C# developers to build a UI in the web with HTML.

To get started most easily, install the Blazor templates available.

> dotnet --version
2.1.403

> dotnet new -i Microsoft.AspNetCore.Blazor.Templates
Restoring packages for C:\Users\Daniel\.templateengine\dotnetcli\v2.1.403\scratch\restore.csproj...
Installing Microsoft.AspNetCore.Blazor.Templates 0.7.0.
Generating MSBuild file C:\Users\Daniel\.templateengine\dotnetcli\v2.1.403\scratch\obj\restore.csproj.nuget.g.props.
Generating MSBuild file C:\Users\Daniel\.templateengine\dotnetcli\v2.1.403\scratch\obj\restore.csproj.nuget.g.targets.
Restore completed in 986.04 ms for C:\Users\Daniel\.templateengine\dotnetcli\v2.1.403\scratch\restore.csproj.

I'm going to create a new Blazor solution.

> mkdir BlazorExample
> cd .\BlazorExample\
> dotnet new sln
> dotnet new blazor -o Blazor.Client
> dotnet new classlib -o Models
> dotnet new webapi -o API
> dotnet sln add Models
> dotnet sln add Blazor.Client
> dotnet sln add API
> cd .\API\
> dotnet add reference ..\Models\
> cd ..\Blazor.Client\
> dotnet add reference ..\Models\

Run the Blazor.Client project

> dotnet run

http://localhost:5000/

Blazor

Awesome! I can run a default project.

Adding a model

To the Models project, add a new class called "Customer". Nothing fancy, just enough for something to exist.

namespace Models
{
    public class Customer
    {
        public string Name { get; set;}
        public string CountryCode { get; set; }
    }
}

Adding an API method

Now to the API project, I'm adding a controller that uses the above model to return a list of customers, as well as a single customer if wanted.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

namespace API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CustomerController : ControllerBase
    {
        [HttpGet()]
        public IEnumerable<Models.Customer> Get()
        {
            return new Models.Customer[] {
                new Models.Customer {
                    Name = "Daniel O",
                    CountryCode = "US"
                },
                new Models.Customer {
                    Name = "Test User",
                    CountryCode = "UK"
                },
                new Models.Customer {
                    Name = "Someone Else",
                    CountryCode = "FR"
                }
            };
        }

        [HttpGet("{id}")]
        public Models.Customer Get(int id)
        {
            return new Models.Customer
            {
                Name = "Someone Else",
                CountryCode = "FR"
            };
        }
    }
}

For ease of use, add the following snippet to Startup.cs inside the "Configure" method.

            app.UseCors(builder => builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());

And change Program.cs to use this method, which will run the API on a different port than the Blazor project is running on.

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://0.0.0.0:5003/")
                .UseStartup<Startup>();

Start up this project in another powershell window:

> dotnet run

Blazor Fetch Data

Back in the Blazor project, there's a page that fetches data. Let's change that page to use the shared model, and to call the API from above.

@page "/fetchdata"
@inject HttpClient Http

<h1>Customers to check up on and see how they're doing.</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (customers == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>CountryCode</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var customer in customers)
            {
                <tr>
                    <td>@customer.Name</td>
                    <td>@customer.CountryCode</td>
                </tr>
            }
        </tbody>
    </table>
}

@functions {
    Models.Customer[] customers;

    protected override async Task OnInitAsync()
    {
        customers = await Http.GetJsonAsync<Models.Customer[]>("http://localhost:5003/api/customer");
    }
}

Blazor

Sharing a model

This is a fantastic concept. I could write a shared model library, and it could be the same models that both server and client side use.

Now this has been advocated before in the .NET world, such as by the efforts of the F# based SAFE Stack. A huge benefit for using the same model is being more confident in type safety, not to mention being able to "find all references" on a class in C#.

Summary

Blazor is well worth looking into. The official docs or Learn Blazor are both fantastic resources. My example code from above is here.