How has .NET Aspire influenced my preferred technology choices?

This is a story about how the .NET Aspire influenced to my preferred technology stack when building native cloud applications to Azure Cloud. I have been working with Azure Cloud for almost 10 years, focusing on PaaS services. This story focuses on developing distributed applications in the Azure PaaS platform.

Before we delve deeper, let's quickly review what .NET Aspire is.

The .NET Aspire 8.0 Preview 1 was officially released on November 15, 2023. Traditionally, developing and deploying to the Cloud has been quite complex, requiring knowledge of various technologies, packages, patterns, and CLI tools. .NET Aspire aims to simplify and enhance the process of building cloud-native applications for the .NET platform. Technology provides a comprehensive set of tools and patterns to streamline the development process. It is particularly well-suited for building distributed microservices and is designed to be cloud-agnostic and highly extensible. While it natively supports the Azure cloud, it can also be extended for use with other cloud platforms. Additionally, the community has developed AWS cloud-compatible .NET Aspire components and capabilities.

✨ The GA version of .NET Aspire is now released and available on May 23, 2024.

My experience with utilizing Azure PaaS Services for hosting applications

Before delving into .NET Aspire, let me provide a brief summary of my Azure adoption from a PaaS application hosting perspective.

My Azure adoption journey (app hosting) before .NET Aspire

🍼 Early adoption - Azure Cloud Services (classic)

As I mentioned, my Azure journey started a little over 10 years ago. In 2013, I had the opportunity to join a project that was already in progress, and the new service was built on top of the Azure Cloud, particularly using the Cloud Services (at that time it wasn't called classic πŸ˜„). This was my first experience in building applications for the Azure Cloud platform using PaaS services.

Cloud Services was a somewhat mixed combination of PaaS and IaaS, with both advantages and disadvantages. Even though it was a PaaS service, you could open a remote desktop connection to a Windows-based VM (Virtual Machine) and see what was happening on the server. This was quite convenient for those familiar with on-premise setups 😊.

The transition to Azure was smooth and effortless. It was easy to start hosting web and worker role-based services in Azure using Cloud Services. Especially if you were already familiar with IIS (Internet Information Services) Web Server configurations and tricks, it was pretty easy to start using Cloud Services. Worker Role was a convenient service for running different kinds of background services, and Web Role was used for web applications. During that period, Cloud Services was the most advanced way to host scalable cloud applications in Azure Cloud.

At that time, DevOps (CI/CD) capabilities weren't as sophisticated as now. It was a right click in Visual Studio > Publish and the wish for the bestπŸš€.

🏰 Foundation - Azure App Services + Azure Functions

In March 2015, Microsoft released the Azure App Service, and a year later Azure Functions. Soon after, all the projects I was involved in started using these new PaaS services for application hosting. The App Service was much easier to manage, scale, deploy, and configure compared to the Cloud Service. The Cloud Service (classic) felt immediately outdated. The App Service was also a true PaaS, as it didn't provide access to virtual machines to see what's happening on the server πŸ™Œ.

Azure DevOps completely transformed the way we automate deployments with a robust CI/CD solution. Initially, my team and I started using Classic Pipelines and later transitioned to YAML-based deployment pipelines.

Since 2015, Azure App Service and Azure Functions have served as the strong foundation for numerous distributed applications and have been key elements in my toolbox when designing and architecting new Azure Cloud solutions.

Next steps - Journey with .NET Aspire

.NET Aspire a new technology in a toolbox

How has .NET Aspire influenced my preferred technology stack?

I started using and following the development of .NET Aspire right after its first public preview, which was almost a year ago. My team and I immediately began building a completely new service using .NET Aspire Preview 1. This distributed service utilized an outbox pattern and was a perfect match for .NET Aspire. This journey has been a very educational and eye-opening experience for both me and the team.

βœ”οΈ Non-Containerized applications -> Containerized applications

As said, Azure App Service has been the core foundation for my projects for many years. We have successfully implemented complex distributed applications on this platform without encountering major issues or obstacles. Although Azure App Service supports containers, we have not experienced significant advantages in using them for our projects. To be precise πŸ€“, we have been using containers because in the Linux-based App Service, applications run in a container, but the containerization process happens automatically in the background.

We have not encountered any technical or business reasons to use containers, as they have not solved any specific problems for us. For instance, portability from one public cloud to another has not been important for our projects. Azure App Service has been well-suited to our needs, and orchestrating distributed services in a complex environment has not been an issue with Azure App Service.

Additionally, working with Docker Compose and Docker Files has felt somewhat complex.

The .NET Aspire has changed my perspectives on containers and how to orchestrate distributed applications.

πŸ‘‰ .NET Aspire enables an easy adoption of containers. It's easy and comfortable. At the moment, .NET Aspire supports Docker and Podman container runtimes.

πŸ‘‰ Use of containers with .NET Aspire is smooth, invisible, and like magic πŸ§™β€β™‚οΈ. Containers are created and published to the Container Registry automatically and everything just works. This experience is similar to using containers with Linux-based Azure App Service. You have also the possibility to configure containers using Docker Compose and Docker File if you like.

πŸ‘‰ Container orchestration via the .NET Aspire Model (AppHost) is a more convenient, comfortable, and readable way to manage service references, environment variables, etc. than using Docker Compose.

πŸ‘‰.NET Aspire enables easy to run and use 3rd. party containers through resources and integrations. If you need to run e.g. KeyCloak container in your solution it's just a few lines of code.

πŸ‘‰ I like the versioning and recovering capabilities of the containers.

βœ”οΈ Azure App Services -> Azure Container Apps Environment

Over the years, I conducted technical feasibility studies for several projects to explore suitable application hosting options for Azure App Services before .NET Aspire. While Azure App Services has generally met our needs, some customers requested an analysis of alternative options.

We found Kubernetes to be overly complex with a steep learning curve, and we were not willing to take on the high level of responsibility for the intricate infrastructure details, especially since most projects lacked a dedicated managed service team to handle the infrastructure.

Azure Container Apps Environment also did not seem like a viable alternative for us, as we typically did not use containers in our projects. Additionally, we had been satisfied with Azure App Services for a long time and didn't have any complaints about it.

Why am I now more interested in the Azure Container Apps environment?

πŸ‘‰ As said earlier .NET Aspire made the use of containers so easy with Azure Container Apps Environment.

πŸ‘‰ Excellent local development experience with .NET Aspire container orchestration.

πŸ‘‰ Azure Container Apps Environment is potentially more cost-effective when running multiple applications and more resource-optimized than Azure App Service.

πŸ‘‰ Configuration of the container's scaling, networking, and environment variables is completely different than in Azure App Service but it's easy to learn. You need to slightly adapt to the way how Kubernetes is configured via YAML.

πŸ‘‰ Azure App Service is a fully managed platform and you can focus on developing applications without worrying about the underlying infrastructure. Azure Container Apps Environment shifts you a bit to a more infrastructure-oriented direction but we're still far away from Kubernetes. With one year experience of running .NET Aspire-powered applications in Azure Container Apps Environment, this hasn't been an issue.

βœ”οΈ Azure Functions -> Worker roles

In the .NET Aspire preview 1, Azure Functions were not supported. In our project, we needed to have background process capability to subscribe to events from the Azure Service Bus. What should we use instead of Azure Functions?

πŸ‘‰ With .NET Aspire, you can easily create a Worker Role (Hosted Service) that runs in a container within the Azure Container Apps Environment. It's convenient and straightforward. This felt like a blast from the past, reminiscent of the Cloud Service (classic) era 😊. Overall, this got us thinking about whether we really need Azure Functions if we can effectively utilize Worker Roles. We're definitely gathering more insights and experience on this.

πŸ‘ŒNote: At the moment, also Azure Functions-based projects can be added to the .NET Aspire orchestration.

βœ”οΈ YAML pipelines -> AZD-powered YAML pipelines

Many times during projects, I have found that creating and configuring YAML-based pipelines can be time-consuming. We often used separate Build and Deploy YAML templates, and sometimes different versions for App Service and Azure Functions.

In July 2023, Microsoft released the Azure Developer CLI (AZD) which was a new tool designed to speed up development workflow for building cloud-native applications on Azure. AZD itself is a separate entity from .NET Aspire but Aspire supports it natively. Essentially, AZD enables application building, container publishing, infrastructure provisioning, and deployment using just a few CLI commands.

Why should you be interested in AZD and why it's a great tool with .NET Aspire?

πŸ‘‰ Azure Developer CLI (AZD) integration with .NET Aspire and Azure Container Apps Environment works smoothly and elegantly. The provisioning of the infra and application deployment from the local environment and pipelines requires just a few commands.

πŸ‘‰ With AZD YAML-based pipelines are more compact and streamlined. Separate Build and Deploy templates are not necessarily needed. You can focus more on developing the application instead of pipelines.

πŸ‘‰ AZD init and infra synth commands analyze the .NET Aspire and Azure Container Apps Environment configuration and automatically create a base Bicep template for infra and YAML-based pipeline for deployment.

βœ”οΈ .NET web development experience -> .NET Aspire web development experience

.NET Aspire enables a next-level developer experience.

πŸ‘‰ Built-in local dashboard UI for your application logs, metrics, and distributed traces. The dashboard is a starting point of your application where to follow what's happening in your. This drives the development experience to the next level.

πŸ‘‰ Outstanding container orchestration without Docker Compose. .NET Aspire App Model provides an awesome interface to configure your containerized services.

πŸ‘‰ Built-in support for Open Telemetry and Distributed Tracing. You can use e.g. Azure Monitor or Prometheus as your telemetry provider.

πŸ‘‰ .NET Aspire makes it easy to run and debug distributed applications in the local development machine. This has been a big challenge earlier.

πŸ‘‰ Pre-configured Health Check Capabilities.

πŸ‘‰ Service discovery is a crucial capability in distributed systems and microservices architectures to enable services to locate and communicate with each other. The .NET Aspire App Model has support for Service Discovery by default. This model enables the easy injecting of service discovery information which streamlines the overall developer experience.

πŸ‘‰ Extensible App Model and growing community.

Summary

⚠️ .NET Aspire and Azure Container Apps Environment will be one of the key components in my toolbox besides Azure App Service and Functions in the future. The right technology must be selected based on need case by case.

Thank you for reading. Please read also my other blog posts regarding .NET Aspire.

Chat with your data - Semantic Kernel-powered RAG app
How to create a Native Code plugin to enable the chatbot’s interaction with external backend services and data storage?
How to create a RAG app using Ollama, and Semantic Kernel
How to create a .NET Aspire-powered RAG application that hosts a chat user interface, API, and Ollama with Phi language model.
How to implement multi-tenant platform with Aspire?
How to design the architecture of the platform which supports multiple independent teams and domain services.
.NET Aspire lessons learned so far
This blog post shares some experiences and lessons learned while using .NET Aspire in Azure.