Skip to content

.NET Aspire Tutorial

Eduardo Fonseca edited this page May 23, 2024 · 1 revision

As of May 21, 2024, .NET Aspire is in preview, meaning lots of things could change.

You can check the official documentation here: https://learn.microsoft.com/en-us/dotnet/aspire/

To see how we are using .NET Aspire in FairPlayCombined, check the following AppHost:

https://github.com/pticostaricags/FairPlayCombined/tree/main/src/FairPlayCombinedSln/FairPlayCombinedSln.AppHost

Setting Up the Program.cs for .NET Aspire AppHost

This tutorial will guide you through the configuration and setup of the Program.cs file for a .NET Aspire application. The Program.cs file is crucial for initializing various projects and resources based on configuration settings. Additionally, it is important to reference the projects in your .csproj file.

Pre-requisite: Reference Projects in .csproj

Before writing the code for the AppHost, ensure that the necessary projects are referenced in your .csproj file. Here is an example of how your .csproj file should look:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsAspireHost>true</IsAspireHost>
    <UserSecretsId>e867248f-3eea-4583-af41-43c0cf232d5b</UserSecretsId>
    <Configurations>Debug;Release;Debug_Enable_Paid_Tests</Configurations>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_Enable_Paid_Tests|AnyCPU'">
    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="SonarAnalyzer.CSharp" Version="9.25.0.90414">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.1" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\FairPlayAdminPortal\FairPlayAdminPortal.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlayBudget\FairPlayBudget.csproj" />
    <ProjectReference Include="..\FairPlayCombined.CitiesImporter\FairPlayCombined.CitiesImporter.csproj" />
    <ProjectReference Include="..\FairPlayCombined.DatabaseManager\FairPlayCombined.DatabaseManager.csproj" />
    <ProjectReference Include="..\FairPlayCombined.LocalizationGenerator\FairPlayCombined.LocalizationGenerator.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlayDating.TestDataGenerator\FairPlayDating.TestDataGenerator.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlayDating\FairPlayDating.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlayShop\FairPlayShop.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlaySocial.TestDataGenerator\FairPlaySocial.TestDataGenerator.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlaySocial\FairPlaySocial.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
    <ProjectReference Include="..\FairPlayTube.VideoIndexing\FairPlayTube.VideoIndexing.csproj" />
    <ProjectReference Include="..\FairPlayTube\FairPlayTube.csproj">
      <ExcludeAssets>all</ExcludeAssets>
    </ProjectReference>
  </ItemGroup>
</Project>

Step 1: Import Necessary Namespaces

First, import the required namespaces:

using FairPlayCombinedSln.AppHost;
using Microsoft.Extensions.Configuration;

Step 2: Initialize the Builder and Add User Secrets

Create a distributed application builder and add user secrets for secure storage of sensitive information:

var builder = DistributedApplication.CreateBuilder(args);
builder.Configuration.AddUserSecrets<Program>();

Step 3: Retrieve Configuration Variables

Retrieve configuration values for Google and PayPal authentication. If any value is missing, an exception is thrown:

var googleAuthClientId = builder.Configuration["GoogleAuthClientId"] ?? throw new InvalidOperationException("'GoogleAuthClientId' not found");
var googleAuthProjectId = builder.Configuration["GoogleAuthProjectId"] ?? throw new InvalidOperationException("'GoogleAuthProjectId' not found");
var googleAuthUri = builder.Configuration["GoogleAuthUri"] ?? throw new InvalidOperationException("'GoogleAuthUri' not found");
var googleAuthTokenUri = builder.Configuration["GoogleAuthTokenUri"] ?? throw new InvalidOperationException("'GoogleAuthTokenUri' not found");
var googleAuthProviderCertUri = builder.Configuration["GoogleAuthProviderCertUri"] ?? throw new InvalidOperationException("'GoogleAuthProviderCertUri' not found");
var googleAuthClientSecret = builder.Configuration["GoogleAuthClientSecret"] ?? throw new InvalidOperationException("'GoogleAuthClientSecret' not found");
var googleAuthRedirectUri = builder.Configuration["GoogleAuthRedirectUri"] ?? throw new InvalidOperationException("'GoogleAuthRedirectUri' not found");

var paypalClientId = builder.Configuration["PayPal:ClientId"] ?? throw new InvalidOperationException("'PayPal:ClientId' not found");
var paypalClientSecret = builder.Configuration["PayPal:ClientSecret"] ?? throw new InvalidOperationException("'PayPal:ClientSecret' not found");

Step 4: Configure SQL Resource

Add a SQL resource to the builder, connecting to the FairPlayCombinedDb database:

IResourceBuilder<IResourceWithConnectionString> sqlResourceWithConnectionString = builder.AddConnectionString("FairPlayCombinedDb");

Step 5: Conditionally Add Projects

Add projects to the builder based on configuration settings. For each project, check the configuration and add it if specified:

FairPlayDating Project

bool addFairPlayDating = Convert.ToBoolean(builder.Configuration["AddFairPlayDating"]);
if (addFairPlayDating)
{
    builder.AddProject<Projects.FairPlayDating>(ResourcesNames.FairPlayDating)
        .WithReference(sqlResourceWithConnectionString);
}

if (Convert.ToBoolean(builder.Configuration["AddFairPlayDatingTestDataGenerator"]))
{
    AddTestDataGenerator(builder, sqlResourceWithConnectionString);
}

FairPlayTube Project

bool addFairPlayTube = Convert.ToBoolean(builder.Configuration["AddFairPlayTube"]);
if (addFairPlayTube)
{
    builder.AddProject<Projects.FairPlayTube>(ResourcesNames.FairPlayTube)
    .WithEnvironment(callback =>
    {
        callback.EnvironmentVariables.Add("GoogleAuthClientId", googleAuthClientId);
        callback.EnvironmentVariables.Add("GoogleAuthProjectId", googleAuthProjectId);
        callback.EnvironmentVariables.Add("GoogleAuthUri", googleAuthUri);
        callback.EnvironmentVariables.Add("GoogleAuthTokenUri", googleAuthTokenUri);
        callback.EnvironmentVariables.Add("GoogleAuthProviderCertUri", googleAuthProviderCertUri);
        callback.EnvironmentVariables.Add("GoogleAuthClientSecret", googleAuthClientSecret);
        callback.EnvironmentVariables.Add("GoogleAuthRedirectUri", googleAuthRedirectUri);

        callback.EnvironmentVariables.Add("PayPal:ClientId", paypalClientId);
        callback.EnvironmentVariables.Add("PayPal:ClientSecret", paypalClientSecret);
    })
    .WithReference(sqlResourceWithConnectionString);
    builder.AddProject<Projects.FairPlayTube_VideoIndexing>(ResourcesNames.FairPlayTubeVideoIndexing)
        .WithReference(sqlResourceWithConnectionString);
}

Additional Projects

Add other projects based on the configuration settings similarly:

bool addFairPlayShop = Convert.ToBoolean(builder.Configuration["AddFairPlayShop"]);
if (addFairPlayShop)
{
    builder.AddProject<Projects.FairPlayShop>(ResourcesNames.FairPlayShop)
    .WithReference(sqlResourceWithConnectionString);
}

bool addCitiesImporter = Convert.ToBoolean(builder.Configuration["AddCitiesImporter"]);
if (addCitiesImporter)
{
    builder.AddProject<Projects.FairPlayCombined_CitiesImporter>(ResourcesNames.CitiesImporter)
        .WithReference(sqlResourceWithConnectionString);
}

bool addFairPlatAdminPortal = Convert.ToBoolean(builder.Configuration["AddFairPlatAdminPortal"]);
if (addFairPlatAdminPortal)
{
    builder.AddProject<Projects.FairPlayAdminPortal>(ResourcesNames.FairPlayAdminPortal)
        .WithReference(sqlResourceWithConnectionString);
}

bool addFairPlaySocial = Convert.ToBoolean(builder.Configuration["AddFairPlaySocial"]);
if (addFairPlaySocial)
{
    builder.AddProject<Projects.FairPlaySocial>(ResourcesNames.FairPlaySocial)
        .WithReference(sqlResourceWithConnectionString);
    if (Convert.ToBoolean(builder.Configuration["AddFairPlaySocialTestDataGenerator"]))
    {
        builder.AddProject<Projects.FairPlaySocial_TestDataGenerator>(ResourcesNames.FairPlaySocialTestDataGenerator)
            .WithReference(sqlResourceWithConnectionString);
    }
}

bool addLocalizationGenerator = Convert.ToBoolean(builder.Configuration["AddLocalizationGenerator"]);
if (addLocalizationGenerator)
{
    builder.AddProject<Projects.FairPlayCombined_LocalizationGenerator>(ResourcesNames.FairPlayCombinedLocalizationGenerator)
        .WithReference(sqlResourceWithConnectionString);
}

bool addFairPlayBudget = Convert.ToBoolean(builder.Configuration["AddFairPlayBudget"]);
if (addFairPlay

Budget)
{
    builder.AddProject<Projects.FairPlayBudget>(ResourcesNames.FairPlayBudget)
        .WithReference(sqlResourceWithConnectionString);
}

Step 6: Build and Run

Build the application and run it asynchronously:

await builder.Build().RunAsync();

Helper Method for Test Data Generator

Add a static method to handle the addition of the test data generator project:

static void AddTestDataGenerator(IDistributedApplicationBuilder builder, IResourceBuilder<IResourceWithConnectionString> sqlServerResource)
{
    var humansPhotosDirectory = builder.Configuration["HumansPhotosDirectory"];
    builder.AddProject<Projects.FairPlayDating_TestDataGenerator>(ResourcesNames.FairPlayDatingTestDataGenerator)
        .WithEnvironment(callback =>
        {
            if (!String.IsNullOrWhiteSpace(humansPhotosDirectory))
            {
                callback.EnvironmentVariables.Add("HumansPhotosDirectory", humansPhotosDirectory);
            }
        }).WithReference(sqlServerResource);
}

Conclusion

By following these steps, you can set up and configure your Program.cs file for a .NET Aspire application, ensuring that necessary projects and resources are properly initialized based on the configuration settings.

Clone this wiki locally