Use Dapr with .NET Aspire
Distributed Application Runtime (Dapr) offers developer APIs that serve as a conduit for interacting with other services and dependencies and abstract the application from the specifics of those services and dependencies. Dapr and .NET Aspire work together to improve your local development experience. By using Dapr with .NET Aspire, you can focus on writing and implementing .NET-based distributed applications instead of spending extra time with local onboarding.
In this guide, you'll learn how to take advantage of Dapr's abstraction and .NET Aspire's opinionated configuration of cloud technologies to build simple, portable, resilient, and secured microservices at-scale on Azure.
Prerequisites
To work with .NET Aspire, you need the following installed locally:
- .NET 8.0 or .NET 9.0
- An OCI compliant container runtime, such as:
- Docker Desktop or Podman. For more information, see Container runtime.
- An Integrated Developer Environment (IDE) or code editor, such as:
- Visual Studio 2022 version 17.9 or higher (Optional)
- Visual Studio Code (Optional)
- C# Dev Kit: Extension (Optional)
- JetBrains Rider with .NET Aspire plugin (Optional)
For more information, see .NET Aspire setup and tooling, and .NET Aspire SDK.
In addition to the prerequisites for .NET Aspire, you will need:
- Dapr version 1.13 or later
To install Dapr, see Install the Dapr CLI. After installing the Dapr CLI, run the dapr init
described in Initialize Dapr in your local environment.
Important
If you attempt to run the app without the Dapr CLI, you'll receive the following error:
Unable to locate the Dapr CLI.
Get started
To get started you need to add the Dapr hosting package to your app host project by installing the 📦 Aspire.Hosting.Dapr NuGet package.
dotnet add package Aspire.Hosting.Dapr
For more information, see dotnet add package or Manage package dependencies in .NET applications.
Add a Dapr sidecar
Dapr uses the sidecar pattern to run alongside your application. The Dapr sidecar runs alongside your app as a lightweight, portable, and stateless HTTP server that listens for incoming HTTP requests from your app.
To add a sidecar to a .NET Aspire resource, call the WithDaprSidecar method on the desired resource. The appId
parameter is the unique identifier for the Dapr application, but it's optional. If you don't provide an appId
, the parent resource name is used instead.
using Aspire.Hosting.Dapr;
var builder = DistributedApplication.CreateBuilder(args);
var apiService = builder
.AddProject<Projects.Dapr_ApiService>("apiservice")
.WithDaprSidecar();
The WithDaprSidecar
method offers overloads to configure your Dapr sidecar options like app ID and ports. In the following example, the Dapr sidecar is configured with specific ports for GRPC, HTTP, metrics, and a specific app ID.
DaprSidecarOptions sidecarOptions = new()
{
DaprGrpcPort = 50001,
DaprHttpPort = 3500,
MetricsPort = 9090
};
builder.AddProject<Projects.Dapr_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WithDaprSidecar(sidecarOptions);
Putting everything together, consider the following example of a .NET Aspire app host project that includes:
- A backend API that declares a Dapr sidecar with defaults.
- A frontend that declares a Dapr sidecar with specific options, such as explict ports.
using Aspire.Hosting.Dapr;
var builder = DistributedApplication.CreateBuilder(args);
var apiService = builder
.AddProject<Projects.Dapr_ApiService>("apiservice")
.WithDaprSidecar();
DaprSidecarOptions sidecarOptions = new()
{
DaprGrpcPort = 50001,
DaprHttpPort = 3500,
MetricsPort = 9090
};
builder.AddProject<Projects.Dapr_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WithDaprSidecar(sidecarOptions);
builder.Build().Run();
The .NET Aspire dashboard shows the Dapr sidecar as a resource, with its status and logs.
Adding the Dapr SDK
To use Dapr APIs from .NET Aspire resources, you can use the 📦 Dapr.AspNetCore/. The Dapr SDK provides a set of APIs to interact with Dapr sidecars.
Note
Use the Dapr.AspNetCore
library for the Dapr integration with ASP.NET (DI integration, registration of subscriptions, etc.). Non-ASP.NET apps (such as console apps) can just use the 📦 Dapr.Client to make calls through the Dapr sidecar.
dotnet add package Dapr.AspNetCore
Once installed into an ASP.NET Core project, the SDK can be added to the service builder.
builder.Services.AddDaprClient();
An instance of DaprClient
can now be injected into your services to interact with the Dapr sidecar through the Dapr SDK.
using Dapr.Client;
namespace Dapr.Web;
public class WeatherApiClient(DaprClient client)
{
public async Task<WeatherForecast[]> GetWeatherAsync(
int maxItems = 10, CancellationToken cancellationToken = default)
{
List<WeatherForecast>? forecasts =
await client.InvokeMethodAsync<List<WeatherForecast>>(
HttpMethod.Get,
"apiservice",
"weatherforecast",
cancellationToken);
return forecasts?.Take(maxItems)?.ToArray() ?? [];
}
}
public record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
InvokeMethodAsync
is a method that sends an HTTP request to the Dapr sidecar. It is a generic method that takes:
- An HTTP verb
- The Dapr app ID of the service to call
- The method name
- A cancellation token
Depending on the HTTP verb, it can also take a request body and headers. The generic type parameter is the type of the response body.
The full Program.cs file for the frontend project shows:
- The Dapr client being added to the service builder
- The
WeatherApiClient
class that uses the Dapr client to call the backend service
using Dapr.Web;
using Dapr.Web.Components;
var builder = WebApplication.CreateBuilder(args);
// Add service defaults & Aspire components.
builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.AddOutputCache();
builder.Services.AddDaprClient();
builder.Services.AddTransient<WeatherApiClient>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.UseOutputCache();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapDefaultEndpoints();
app.Run();
For example, in a Blazor project, the WeatherApiClient
class can be injected into a integration and used to call the backend service.
@page "/weather"
@attribute [StreamRendering(true)]
@attribute [OutputCache(Duration = 5)]
@inject WeatherApiClient WeatherApi
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data loaded from a backend API service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await WeatherApi.GetWeatherAsync();
}
}
When the Dapr SDK is used, the Dapr sidecar is called over HTTP. The Dapr sidecar then forwards the request to the target service. While the target service runs in a separate process from the sidecar, the integration related to the service runs in the Dapr sidecar and is responsible for service discovery and routing the request to the target service.
Dapr and .NET Aspire
At first sight Dapr and .NET Aspire may look like they have overlapping functionality, and they do. However, they both take a different approach. .NET Aspire is an opinionated approach on how to build distributed applications on a cloud platform. Dapr is a runtime that abstracts away the common complexities of the underlying cloud platform. It relies on sidecars to provide abstractions for things like configuration, secret management, and messaging. The underlying technology can be easily switched out through configuration files, while your code does not need to change.
.NET Aspire makes setting up and debugging Dapr applications easier by providing a straightforward API to configure Dapr sidecars, and by exposing the sidecars as resources in the dashboard.
Explore Dapr components with .NET Aspire
Dapr provides many built-in components, and when you use Dapr with .NET Aspire you can easily explore and configure these components. Don't confuse these components with .NET Aspire integrations. For example, consider the following:
- Dapr—State stores: Call AddDaprStateStore to add a configured state store to your .NET Aspire project.
- Dapr—Pub Sub: Call AddDaprPubSub to add a configured pub sub to your .NET Aspire project.
- Dapr—Components: Call AddDaprComponent to add a configured integration to your .NET Aspire project.