Over the pun yet? Me neither! While we wait for the myrth to subside, I'll share the lessons I learned building my first Blazor Server app. But first, some context. I've just finished a small side project at work which was off the radar, meaning I had my choice of technology. Having recently returned from DDD Reading 2019 where Marco De Sanctis gave a brilliant talk on Building Single Page apps with Blazor and ASP.Net Core 3.0, I was inspired!

🎄🎄 Charity Advent Calendar 🎄🎄

The brief was to quickly build an Advent Calendar which only employees could play. The calendar runs each year, but this year in an effort to get more players, I created a digital version. It needed to store guesses, display a leaderboard and display content from a database.

The talk at DDD showcase how simple creating this kind of thing was using Blazor. I started with the single page template that ships with Blazor. I added MatBlazor, which gave me a boat-load of Material styled Blazor components to work with. This made the UI super-simple to build. I was off to a flyer.

Authentication

The site is running in Azure and needed to only be accessible by employees. I was aware of "turn-key" authentication in Azure, but wondered what the Blazor story would be. After enabling authentication of the App Service in Azure, I added the following to the startup.cs file in the root

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => Configuration.Bind("AzureAd", options));

services.AddControllersWithViews(options =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

Adding an azureAD section to the appsettings.json with the following was all the code needed;

 "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "youraddomainname",
    "TenantId": "the id of your tenant",
    "ClientId": "the id of the client registered in your ad",
    "CallbackPath": "/signin-oidc"
  },

With these two snippets of code, my Blazor app was ready to authenticate with our AD. This provided the authentication and basic user information to use in the calendar.

Having integrated Angular apps in to the very same AD with a lot of blood, sweat, tears and dev tantrums, I was amazed how simple this was to implement, not to mention how "It Just Worked" ™

EFCore and Blazor Server

Of course it wasn't all plain sailing. I used EF Core to talk to SQL Server, which caused a number of issues. In hindsight, Dapper or something a little more lightweight would have been a better option here. The main issue I had was my lack of understanding of how Blazor works with it's "server".

Blazor Server persists a connection to connected clients using SignalR. So, as EFCore gets entities from the database, it tracks them to allow changes to be persisted back to the database. The Advent calendar allowed players to guess what was behind each door. They could also update their guesses. As players updated their guess EFCore began a battle with itself and the state persisted by Blazor. As soon as a tracked entity was updated the output window in Visual Studio began to spew update and select statements for the edited guess. It took a while to figure it out, but ultimately the fix was simple. For queries that presented data back to the user I needed to add, AsNoTracking() to the queries. So

context.Guesses.ToList();

becomes

context.Guesses.AsNoTracking().ToList();

This prevented EFCore tracking the state of entities. As soon as they left the database EFCore 'forgot' about them.

Burning Money for Charity

As this was a charity advent calendar, it was more important than ever to keep the Azure costs to a minimum. While investigating the options for the db (SQL Server to allow for simple internal reporting) I stumbled upon Azure's new Serverless option. It looked perfect. To quote the docs

"Azure SQL Database serverless is a new compute tier that optimises price-performance and simplifies performance management for databases with intermittent, unpredictable usage. Serverless automatically scales compute for single databases based on workload demand and bills for compute used per second."

As demand for the app was expected to be low and intermittent, this looked like the option for me.

However, in the first 4 days, hosting costs for the db alone were £20 with the end of month cost predicted to be around £300! I scaled down to a cheapest 'Basic' tier (2GB & 5DTUs) and the cost has barely moved in the proceeding 8 days!

I'm not quite sure why this ended up being so expensive. I suspect it was something to do with SignalR holding open a connection to the db and incurring additional cost that way.

Either that or I have misunderstood the concept of serverless and intermittent use.

Of course it could be that the Advent calendar was an underground hit, which I'm secretly pleased to say it was 😊.

Blazor server was super simple to get started with. If you have a background with Razor or Razor Pages you will feel at home here. I think once this moves to the browser with the Blazor WebAssembly (coming soon), Angluar and the other JS frameworks will have some significant competition.