Learn how was built, an application used daily, and the reason the technologies used were selected.
I like to read. I read while commuting, at home, in the morning, or in the evening. I read books of course, but I also a lots of blog posts, and articles to stay up to date with the technologies. And from time to time, a questions or a topic comes out and I remember that I read something about it but I can't remember where. So I decided to build a simple app to help me keep track of the articles I read, with my personal thoughts about it. I called it NoteBookmark. I then use it to write my weekly Reading Notes post and be able to find back any articles I read.
In this post, I will share how I build the NoteBookmark explaining the choices I made and the technologies I used. It's a real application that I use everyday, it's still in progress, and it's open source. You can find the source code on my GitHub repository NoteBookmark
The Architecture
The NoteBookmark is a simple application. There is a frontend, a backend, and a data storage. The frontend is a .NET Blazor webapp, the backend is a .NET minimal API, and the data is stored in Azure Storage table. The frontend and the backend are hosted in Azure Container Apps.
Azure Container Apps provides built-in authentication and authorization features (sometimes referred to as "Easy Auth"), to secure your external ingress-enabled container. The frontend is secured with Easy Auth and the backend API is not exposed to the internet.
Why this tech stack?
I choose Azure Container Apps because it's a fully managed service that allows me to run my containerized applications without having to manage the underlying infrastructure. I'm the only user of the NoteBookmark, so I can scale it down to 0 when I don't use it, and at the same time save some money. The authentication and authorization features are built-in and easy to configure; no code required. The fact that the API is not exposed to the internet is a plus for me. I don't have to worry about securing it, and I can focus on the features I want to build.
The Azure Storage table is a simple and cheap way to store the data. I don't need a relational database for this application. The Azure Storage table is a NoSQL key-value store that allows me to store and retrieve data quickly. It's also easy to use and integrate with the .NET SDK. If needed I can use the Azure Portal or Azure Storage Explorer to see the data, that's always nice mostly when you are debugging.
The .NET Solution
I used .NET Aspire for this project. .NET Aspire is a set of tools and guidance to help you build modern .NET applications. It provides a set of best practices, tools, and templates to help you get started quickly. I used the dotnet new aspire command to create the solution. Then I added a minimal API dotnet new webapi, a class library project dotnet new classlib, and a Blazor webapp that uses FluentUi components dotnet new fluentblazor.
NoteBookmark/
├── NoteBookmark.Api # Minimal API project
├── NoteBookmark.AppHost # Aspire orchestrator project
├── NoteBookmark.BlazorApp # Blazor webapp project
├── NoteBookmark.Domain # Class library project
└── NoteBookmark.ServiceDefaults # Aspire service defaults project
Why those choices?
I choose the minimal API because it's a lightweight version of ASP.NET Core that allows me to build simple APIs quickly. I don't need all the features of a full ASP.NET Core application for this project. The minimal API is easy to use and configure, and it's perfect for building microservices or small APIs.
FluentUi Blazor is a set of components that allows me to build modern web applications with a consistent design and user experience. I like using it so my applications look good while I can focus on the features I want to build. Blazor is a great choice to build web applications with C# and I used the server version because I knew it would be running in a container.
The class library project contains the classes that are shared between the frontend and the backend.
Aspire provides an orchestrator project `AppHost` that allows us to describe all the services and there interactions in a single place in C#! It's very useful while working locally as a simple `F5` will start all the services and take care of settings all the required ports and configurations. And as we will see later, it also helps to deploy the application to Azure Container Apps, by creating a manifest.
Here is the AppHost project file:
var builder = DistributedApplication.CreateBuilder(args);
var connectionString = builder.AddConnectionString("data-storage-connstr");
var api = builder.AddProject<NoteBookmark_Api>("api")
.WithEnvironment("data-storage-connstr",connectionString);
builder.AddProject<NoteBookmark_BlazorApp>("blazor-app")
.WithReference(api)
.WithExternalHttpEndpoints();
builder.Build().Run();
Note here that only the "blazor-app" as .WithExternalHttpEndpoints() not the "api". The API is not exposed to the internet, only the frontend is. The API is only accessible from the frontend.
Many Azure services can host an APIs and web-app. Like if often the case, we only want allowed users to access the API. We could have implement security in code, passing token between the webapp and the API. It might be implement in the future to create a more granular access, but for now, I choose to use the built-in Easy Auth feature of Azure Container Apps. This way, the webapp is secured and it doesn't require any code. The API is not exposed to the internet, so it's not accessible from the outside, only authenticated users from the webapp can access it, using the internal network of the Azure Container Apps.
Deployment and Infrastructure as Code (IaC)
I used the Azure Developer CLI (azd) to deploy the NoteBookmark to Azure Container Apps. The Azure Developer CLI is a set of tools that allows you to deploy and manage Azure resources from the command line. Using the commands azd init and azd up I was able to deploy the NoteBookmark to Azure Container Apps in a few minutes.
Like mentioned earlier, I wanted the application to scale down to zero when not used. I used the command azd infra synth to generate the infrastructure as code (IaC) for the entire solution. The IaC is a set of YAML files that describe the resources needed to deploy the NoteBookmark. In the NoteBookmark.AppHost folder I have a infra folder that contains to YAML files: api.tmpl.yaml and blazor-app.tmpl.yaml. To make the application scale down to zero, I change the value of minReplicas to 0 in the two files.
scale:
minReplicas: 0
Then using the same azd up command I was able to re-deploy the changes to Azure. This time it was much faster because the resources were already created.
CI/CD Pipeline
That is great for a "one shot" deployment, but how to implement a CI/CD pipeline? Because the code is on GitHub, so I used GitHub Actions to automate the deployment. Once again the Azure Developer CLI comes to the rescue. I used the azd pipeline config command to create a GitHub Action workflow file, set all the secrets in GitHub. Now each time I push to the main branch, it will trigger a deployment.
Azure Container Apps and Easy Auth
Setting up the Easy Auth could be done entirely trough the Azure Portal. Open the Azure Container Apps blazor-app resource. From the left menu, go to the "Authentication" the the "Settings" section. Click on "Add provider" and select "Microsoft Entra". Fill the form with the required information , and voilà! The frontend is now secured with Easy Auth. This mean that you will be prompted to login with your Microsoft account before accessing the application, you wont even see the home page before being authenticated.
Wrapping up
The project totally usable, I use it daily! Of course there is features to add, and tests to write. Give it a try! Go to the GitHub repo, deploy it, and leave feedback using the GitHub Issues tab. It's an open source project, so feel free to contribute, or use it as a base for your own project. I hope this post will help you to build your own application using Azure Container Apps and the .NET Aspire.
Learn more about
Updated Feb 10, 2025
Version 3.0FBoucher
Brass Contributor
Joined September 02, 2016
Apps on Azure Blog
Follow this blog board to get notified when there's new activity