Getting Started with .NET Aspire for Production Ready Cloud Native Apps

.NET Aspire Banner

The demand for cloud-native applications has soared due to the impressive features offered by cloud services, such as high availability, scalability, durability, low maintenance, easy configurability, robust security, and efficient monitoring tools. Despite these advantages, designing a cloud-native application can be a complex and time-consuming task, requiring careful consideration of various factors. Developers often find themselves grappling with decisions about technologies, tools, stacks, and cloud services, leading to confusion and challenges in building future-proof cloud solutions.

Recognizing these struggles, developers have expressed the need for a more accessible solution. Building applications for the cloud has been perceived as too challenging, diverting developers from their primary focus on business logic. The good news is that there’s an incredible solution to simplify cloud-ready application development and solution design – introducing .NET Aspire.

.NET Aspire is a user-friendly solution designed for crafting applications ready for the cloud. It simplifies the development process, allowing developers to focus on their core business logic. Packaged as a set of NuGet packages, .NET Aspire handles specific cloud-related concerns. Whether you’re dealing with databases, messaging, or caching, .NET Aspire has you covered. It’s your go-to stack for creating cloud-ready, observable, and production-ready applications.

Cloud-native applications often need to connect to diverse services, including databases, storage and caching solutions, messaging providers, and other web services. .NET Aspire is crafted to simplify the process of establishing connections and configurations across these services.

In this article, we will learn about .NET Aspire, getting started, and developing a .NET Aspire app, a cloud-ready application using Visual Studio.

.NET Aspire is available in preview with .NET and will be released generally as part of .NET 8 next year.

Getting Started with .NET Aspire

In this section, we create a project with .NET Aspire. Let’s commence.

Prerequisites

Alternatively, we can use Visual Studio Code as IDE.

We will Install the Preview Version of Visual Studio 2022.

Visual Studio Installer

Then, we will install the .NET Aspire workload from the command as shown below.

dotnet workload install aspire

Install .NET Aspire

We need to restart the machine to get the .NET Aspire project templates. Let’s open the Visual Studio Preview after restart.

New Project in Visual studio

We will select the .NET Aspire Starter Application from the project template.

Configure project

We will input a solution name as MyFirstAspireApp.

Additional information in project

Select .NET 8.0 LTS, and also check the use of Redis for caching (requires Docker) option.

Our .NET Aspire project was created successfully. Let’s explore the projects and structure of the solution.

Solution explorer

Solution Folder Structure

└───📂 MyFirstAspireApp
     ├───📂 MyFirstAspireApp.ApiService
     │    ├───📂 Properties
     │    │    └─── launchSettings.json
     │    ├─── appsettings.Development.json
     │    ├─── appsettings.json
     │    ├─── MyFirstAspireApp.ApiService.csproj
     │    └─── Program.cs
     ├───📂 MyFirstAspireApp.AppHost
     │    ├───📂 Properties
     │    │    └─── launchSettings.json
     │    ├─── appsettings.Development.json
     │    ├─── appsettings.json
     │    ├─── MyFirstAspireApp.AppHost.csproj
     │    └─── Program.cs
     ├───📂 MyFirstAspireApp.ServiceDefaults
     │    ├─── MyFirstAspireApp.ServiceDefaults.csproj
     │    └─── Extensions.cs
     ├───📂 MyFirstAspireApp.Web
     │    ├───📂 Components
     │    │    ├───📂 Layout
     │    │    │    ├─── MainLayout.razor
     │    │    │    ├─── MainLayout.razor.css
     │    │    │    ├─── NavMenu.razor
     │    │    │    └─── NavMenu.razor.css
     │    │    ├───📂 Pages
     │    │    │    ├─── Counter.razor
     │    │    │    ├─── Error.razor
     │    │    │    ├─── Home.razor
     │    │    │    └─── Weather.razor
     │    │    ├─── _Imports.razor
     │    │    ├─── App.razor
     │    │    └─── Routes.razor
     │    ├───📂 Properties
     │    │    └─── launchSettings.json
     │    ├───📂 wwwroot
     │    │    ├───📂 bootstrap
     │    │    │    ├─── bootstrap.min.css
     │    │    │    └─── bootstrap.min.css.map
     │    │    ├─── app.css
     │    │    └─── favicon.png
     │    ├─── appsettings.Development.json
     │    ├─── appsettings.json
     │    ├─── MyFirstAspireApp.Web.csproj
     │    ├─── Program.cs
     │    └─── WeatherApiClient.cs
     └─── MyFirstAspireApp.sln

.NET Aspire project template will create four projects.

  • ProjectName.ApiService: This ASP.NET Core Minimal API project serves as the data provider for the front end. It relies on the shared ProjectName.ServiceDefaults project.
  • ProjectName.AppHost: As the orchestrator project, it is designed to interconnect and configure various projects and services within your application. Set this orchestrator as the Startup project, and it has dependencies on both ProjectName.ApiService and ProjectName.Web projects.
  • ProjectName.ServiceDefaults: A shared .NET Aspire project responsible for managing configurations reused across your solution’s projects. It handles aspects related to resilience, service discovery, and telemetry.
  • ProjectName.Web: This ASP.NET Core Blazor App project comes with default .NET Aspire service configurations and depends on the ProjectName.ServiceDefaults project.

Starter .NET Aspire Project

We can delve further into the Aspire Solution. The two projects, AppHost and ServiceDefaults, play vital roles for .NET Aspire and it set to True for IsAspireHost and IsAspireSharedProject.

Aspire host

Aspire shared project

The ProjectName.Web project is a conventional ASP.NET Core Blazor App that delivers the frontend user interface. On the other hand, the ProjectName.ApiService project follows the standard ASP.NET Core Minimal API template structure. Both projects rely on the shared ProjectName.ServiceDefaults project, which centrally manages configurations reused across various projects in your solution.

Let’s explore the AppHost project’s program.cs file.

var builder = DistributedApplication.CreateBuilder(args);

var cache = builder.AddRedisContainer("cache");

var apiservice = builder.AddProject<Projects.MyFirstAspireApp_ApiService>("apiservice");

builder.AddProject<Projects.MyFirstAspireApp_Web>("webfrontend")
    .WithReference(cache)
    .WithReference(apiservice);

builder.Build().Run();

The code creates an IDistributedApplicationBuilder using DistributedApplication.CreateBuilder(), then adds a Redis container named “cache” using AddRedisContainer, storing the result in a variable named cache of type IResourceBuilder<RedisContainerResource>. It adds the ProjectName.ApiService project to the application model using AddProject, configuring service discovery and communication. Another AddProject call adds the ProjectName.Web project and multiple WithReference calls to pass the cache and apiservice variables. The app is then built and run using DistributedApplication.Run(), launching the app and its dependencies.

Similarly, The service defaults project provides an extension method called AddServiceDefaults on the IHostApplicationBuilder type. It serves as a baseline, and you have the flexibility to customize it according to your specific requirements.

We will explore the front-end project’s program.cs.

using MyFirstAspireApp.Web;
using MyFirstAspireApp.Web.Components;

var builder = WebApplication.CreateBuilder(args);

// Add service defaults & Aspire components.
builder.AddServiceDefaults();
builder.AddRedisOutputCache("cache");

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

builder.Services.AddHttpClient<WeatherApiClient>(client=> client.BaseAddress = new("http://apiservice"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
}

app.UseStaticFiles();

app.UseAntiforgery();

app.UseOutputCache();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();
    
app.MapDefaultEndpoints();

app.Run();

Cache

The code initiates the configuration process by invoking AddServiceDefaults, establishing the shared defaults for the application. Subsequently, AddRedisOutputCache is called, using the identical connectionName employed when integrating the Redis container “cache” into the application model. This configuration sets up the app to utilize Redis for output caching. Lastly, AddHttpClient is invoked, setting up the HttpClient.BaseAddress as “http://apiservice.” This name corresponds to the one used during the addition of the API project to the application model. With service discovery in place, it automatically resolves to the correct address for the API project.

Let’s run the project :). Ensure that the AppHost project is set as a startup project and Docker is running.

Microsoft visual studio

You will see the running application as shown.

Running application

We will open the URL as shown in the above console: http://localhost:15073/

This is the URL of the dashboard of .NET Aspire.

URL Dashboard

The dashboard will show two running applications: aspservice and webfrontend.

The dashboard is quite comprehensive, with several options like Projects, containers, executables, logs traces, and metrics.

You can check container endpoints of the applications, view environment details, logs, and many more. This is one of the amazing features of .NET Aspire. Let’s open my webfrontend application.

Hello world projact

Congratulations!! We successfully run the .NET Aspire application.

Furthermore, you can see in our desktop docker that a docker image is created and the container is running.

Docker Image

Running container

This is how we can create .NET Aspire, a cloud-ready solution for building observable, production-ready, distributed applications.

Conclusion

.NET Aspire emerges as a powerful solution for simplifying cloud-ready application development and solution design. With its opinionated, cloud-native stack, it streamlines the complexities associated with building observable, production-ready, and distributed applications. By providing a set of NuGet packages that handle specific cloud-native concerns, .NET Aspire facilitates the creation of microservices-based applications, promoting high availability, scalability, and durability. The framework addresses the challenges developers face in choosing technologies, tools, stacks, and cloud services, offering a cohesive approach to future-proof cloud solutions.

.NET Aspire’s modular architecture, as demonstrated in the provided examples, allows developers to easily connect and configure different projects and services within their applications. Whether it’s handling service defaults, incorporating Redis for output caching, or configuring HttpClient for seamless communication between projects, .NET Aspire streamlines the development process. Embracing .NET Aspire not only simplifies the complexities of cloud-native application development but also establishes a foundation for building robust, maintainable, and scalable solutions in the ever-evolving landscape of software development.

Source Code: https://github.com/rijwanansari/MyFirstAspireApp

References


Similar Articles