Skip to content

Solution Walkthrough

We’ve created a new aspire starter application. The solution explorer should look something like this:

  • DirectoryWalkthrough.ApiService/
  • DirectoryWalkthrough.AppHost/
  • DirectoryWalkthrough.ServiceDefaults/
  • DirectoryWalkthrough.Web/

App Host

The Orchestration project AppHost is the entry point and where we configure our services, databases, and other resources. As I mentioned before if you’ve used ASP.NET Core’s WebHostBuilder this will feel very familiar.

We can see that the template creates a DistributedApplicationBuilder and adds our projects to the builder. To add a project we use the AddProject method, and pass the project reference which we get from the Projects metadata object as the generic argument. As long as the AppHost has a reference to the project in the Walkthrough.AppHost.csproj file our projects will appear as properties from the Projects global object.

var builder = DistributedApplication.CreateBuilder(args);
var apiService = builder.AddProject<Projects.Walkthrough_ApiService>("apiservice");
builder.AddProject<Projects.Walkthrough_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService);

project metadat

We can see that when calling AddProject the method it will return a IResouceBuilder<ProjectResource>, the ProjectResource is specific to adding .NET projects, but the IResourceBuilder interface is used for all resources. We can then pass our returned IResourceBuilder to other projects as references. This is happening in the above code where we pass the apiService to the webfrontend project. This will handle the networking between the two projects, similar to a docker compose configuration:

services:
apiService:
image: ${DOCKER_REGISTRY-}walkthrough_apiservice
build:
context: .
dockerfile: ApiService/Dockerfile
webFrontend:
image: ${DOCKER_REGISTRY-}walkthrough_webfrontend
build:
context: .
dockerfile: WebFrontend/Dockerfile
depends_on:
- apiService

Running the AppHost

Finally in the Program.cs file of the AppHost we see the call to build and run the Distributed Application:

builder.Build().Run();

Before getting into the Service Defaults project, lets run the AppHost and take a look at the .NET Aspire dashboard.

Making sure the AppHost project is the startup project either hit F5 or run dotnet run from the AppHost directory.

runnning apphost

After starting AppHost, a browser window should open which is directed to the Aspire dashboard.

aspire dashboard

The Dashboard

The dashboard has a lot of information about the state of our services, events, logs, health checks, and links to launch swagger or frontend projects. If we click on the https link for the webfrontend project we’re brought to a typical Blazor application.

If we check the Program.cs file in the Web project we can see a base address is being added to a http client service

builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
// This URL uses "https+http://" to indicate HTTPS is preferred over HTTP.
// Learn more about service discovery scheme resolution at https://aka.ms/dotnet/sdschemes.
client.BaseAddress = new("https+http://apiservice");
});

We’ll get into how this works in the next section, but for now by checking the GetWeatherAsync method of the WeatherApiClient we can see that the Web project is getting its weather information from the ApiService service.

await foreach (var forecast in httpClient.GetFromJsonAsAsyncEnumerable<WeatherForecast>("/weatherforecast", cancellationToken))
{
if (forecasts?.Count >= maxItems)
{
break;
}
if (forecast is not null)
{
forecasts ??= [];
forecasts.Add(forecast);
}
}
return forecasts?.ToArray() ?? [];

In the web browser click the Weather link in the Blazor app and return to the dashboard. We’ve triggered requests from both services so there should be information to view in the different tabs.

  • Console - Shows the same logs you would see in the terminal when running a .NET application.
  • Structured - Shows logs which can be filtered by keywords, log levels, categories, services, and more as well as a details tab with more information about the log.
  • Metrics - Shows the metrics for the different services and can be filtered by service. There are options to view metrics in a graph or table format.
  • Traces - Shows the traces of the requests that have been made to the services. An incredibly useful tab for debugging, we can see when we navigated to Weather tab and even click into the details view to see a waterfall chart of the different requests made. traces

Service Defaults

Each service project in your aspire solution should have a reference to the ServiceDefaults project. The extension method builder.AddServiceDefaults() should be called by each service which adds the following:

  • OpenTelemetry metrics and tracing (a lot of what we just went through in the dashboard).
  • Default health check endpoints.
  • Service discovery functionality.
  • Configures HttpClient to work with service discovery.

If we look at the AddServiceDefaults() method we can see the previously mentioned features being added.

public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
{
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
// Turn on resilience by default
http.AddStandardResilienceHandler();
// Turn on service discovery by default
http.AddServiceDiscovery();
});
return builder;
}