-
Notifications
You must be signed in to change notification settings - Fork 152
[DRAFT] Dapr content #894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DRAFT] Dapr content #894
Changes from 5 commits
78fce13
d11d48f
8dcb3fa
2006540
6dc0916
9664f1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
--- | ||
title: Use Dapr with .NET Aspire | ||
description: Learn how to use Dapr with .NET Aspire | ||
ms.date: 05/14/2024 | ||
ms.topic: overview | ||
--- | ||
|
||
# Use Dapr with .NET Aspire | ||
|
||
[Distributed Application Runtime (Dapr)](https://docs.dapr.io/) offers developer APIs that run as a sidecar process and abstract away the common complexities of the underlying cloud platform. 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. | ||
|
||
[!INCLUDE [aspire-prereqs](../includes/aspire-prereqs.md)] | ||
|
||
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](https://docs.dapr.io/getting-started/install-dapr-cli/). After installing the Dapr CLI, run the `dapr init` described in [Initialize Dapr in your local environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/). | ||
|
||
## Get started | ||
|
||
To get started you need to add the Dapr hosting package to your app host project by installing the [Aspire.Hosting.Dapr](https://www.nuget.org/packages/Aspire.Hosting.Dapr) NuGet package. | ||
|
||
### [.NET CLI](#tab/dotnet-cli) | ||
|
||
```dotnetcli | ||
dotnet add package Aspire.Hosting.Dapr --prerelease | ||
``` | ||
|
||
### [PackageReference](#tab/package-reference) | ||
|
||
```xml | ||
<PackageReference Include="Aspire.Hosting.Dapr" | ||
Version="[SelectVersion]" /> | ||
``` | ||
|
||
--- | ||
|
||
For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). | ||
|
||
The Dapr resource is added to the .NET Aspire distributed application builder using the `AddDapr()` method. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now implicit when calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
An overload of the `AddDapr()` method that accepts Dapr options is available. For most applications, the default options will suffice. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.AppHost/Program.cs" range="4"::: | ||
|
||
Dapr uses the Sidecar pattern to run alongside your application. The Dapr sidecar is a lightweight, portable, and stateless HTTP server that listens for incoming HTTP requests from your application. The sidecar is responsible for managing the lifecycle of your application, including service discovery, configuration, and secrets management. To add a sidecar to a .NET Aspire resource by using the `WithDaprSidecar(string appId)` method. The `appId` parameter is the unique identifier for the Dapr application. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Dapr sidecar doesn't start/stop your application, so I'm not sure I'd say that it manages its "lifecycle" so much as it serves as a conduit for interacting with other services and dependencies and abstracts the application from the specifics of those services and dependencies. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ #939 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should lead with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @NicoVermeir Would you be able to update your code to reflect this? |
||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.AppHost/Program.cs" range="18-21" highlight="21"::: | ||
|
||
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. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.AppHost/Program.cs" range="6-16" highlight="1-7,11"::: | ||
|
||
Putting everything together, here's an example of a .NET Aspire app host project which includes: | ||
|
||
- A backend that declares a Dapr sidecar with specific ports and app ID. | ||
- A frontend that declares a Dapr sidecar with a specific app ID and default ports. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.AppHost/Program.cs"::: | ||
|
||
The .NET Aspire dashboard will shows the Dapr sidecar as a resource, with its status and logs. | ||
|
||
:::image type="content" source="media/aspire-dashboard-dapr-sidecar-resources.png" lightbox="media/aspire-dashboard-dapr-sidecar-resources.png" alt-text=".NET Aspire dashboard showing Dapr sidecar resources"::: | ||
|
||
## Adding the Dapr SDK | ||
|
||
To use Dapr APIs from .NET Aspire resources you can use the [Dapr SDK for ASP.NET Core](https://www.nuget.org/packages/Dapr.AspNetCore/). The Dapr SDK provides a set of APIs to interact with Dapr sidecars. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A note that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ #939 |
||
|
||
### [.NET CLI](#tab/dotnet-cli) | ||
|
||
```dotnetcli | ||
dotnet add package Dapr.AspNetCore | ||
``` | ||
|
||
### [PackageReference](#tab/package-reference) | ||
|
||
```xml | ||
<PackageReference Include="Dapr.AspNetCore" | ||
Version="[SelectVersion]" /> | ||
``` | ||
|
||
--- | ||
|
||
Once installed into an ASP.NET Core project, the SDK can be added to the service builder. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.Web/Program.cs" range="15"::: | ||
|
||
An instance of `DaprClient` can now be injected into your services to interact with the Dapr sidecar through the Dapr SDK. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.Web/WeatherApiClient.cs" highlight="9-10"::: | ||
|
||
`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 and 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 and the `WeatherApiClient` class that uses the Dapr Client to call the backend service. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.Web/Program.cs" highlight="15,17"::: | ||
|
||
In, for example, a Blazor project the `WeatherApiClient` class can be injected into a component and used to call the backend service. | ||
|
||
:::code language="csharp" source="snippets/Dapr/Dapr.Web/Components/Pages/Weather.razor" highlight="5,47"::: | ||
|
||
What actually happens when the Dapr SDK is used is that the Dapr sidecar is called over HTTP. The Dapr sidecar then forwards the request to the target service. The target service can be running in the same process as the Dapr sidecar or in a different process. The Dapr sidecar is responsible for service discovery and routing the request to the target service. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: the target service typically isn't running in the same process as the sidecar. Or, rather, the component related to a service may run in the Dapr sidecar, but that will forward calls (e.g. pub-sub, output bindings, etc.) to some other service. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ #939 |
||
|
||
## 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 opiniated 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. | ||
|
||
[.NET Aspire Dapr sample app](/samples/dotnet/aspire-samples/aspire-dapr/) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Dapr.ServiceDefaults\Dapr.ServiceDefaults.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
// Add service defaults & Aspire components. | ||
builder.AddServiceDefaults(); | ||
|
||
// Add services to the container. | ||
builder.Services.AddProblemDetails(); | ||
|
||
var app = builder.Build(); | ||
|
||
// Configure the HTTP request pipeline. | ||
app.UseExceptionHandler(); | ||
|
||
var summaries = new[] | ||
{ | ||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" | ||
}; | ||
|
||
app.MapGet("/weatherforecast", () => | ||
{ | ||
var forecast = Enumerable.Range(1, 5).Select(index => | ||
new WeatherForecast | ||
( | ||
DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | ||
Random.Shared.Next(-20, 55), | ||
summaries[Random.Shared.Next(summaries.Length)] | ||
)) | ||
.ToArray(); | ||
return forecast; | ||
}); | ||
|
||
app.MapDefaultEndpoints(); | ||
|
||
app.Run(); | ||
|
||
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) | ||
{ | ||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/launchsettings.json", | ||
"profiles": { | ||
"http": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"launchUrl": "weatherforecast", | ||
"applicationUrl": "http://localhost:5463", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
}, | ||
"https": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"launchUrl": "weatherforecast", | ||
"applicationUrl": "https://localhost:7487;http://localhost:5463", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning" | ||
} | ||
}, | ||
"AllowedHosts": "*" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<IsAspireHost>true</IsAspireHost> | ||
<UserSecretsId>0bd3d839-67a8-422d-aee2-bd9f1c0556a1</UserSecretsId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Dapr.ApiService\Dapr.ApiService.csproj" /> | ||
<ProjectReference Include="..\Dapr.Web\Dapr.Web.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.0-preview.7.24251.11" /> | ||
<PackageReference Include="Aspire.Hosting.Dapr" Version="8.0.0-preview.7.24251.11" /> | ||
IEvangelist marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using Aspire.Hosting.Dapr; | ||
|
||
var builder = DistributedApplication.CreateBuilder(args); | ||
builder.AddDapr(); | ||
|
||
DaprSidecarOptions sidecarOptions = new () | ||
{ | ||
AppId = "apiservice-dapr", | ||
DaprGrpcPort = 50001, | ||
DaprHttpPort = 3500, | ||
MetricsPort = 9090 | ||
}; | ||
|
||
var apiService = builder | ||
.AddProject<Projects.Dapr_ApiService>("apiservice") | ||
.WithDaprSidecar(sidecarOptions); | ||
|
||
builder.AddProject<Projects.Dapr_Web>("webfrontend") | ||
.WithExternalHttpEndpoints() | ||
.WithReference(apiService) | ||
.WithDaprSidecar("webfrontend-dapr"); | ||
|
||
builder.Build().Run(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/launchsettings.json", | ||
"profiles": { | ||
"https": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "https://localhost:17181;http://localhost:15032", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development", | ||
"DOTNET_ENVIRONMENT": "Development", | ||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21181", | ||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22225" | ||
} | ||
}, | ||
"http": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "http://localhost:15032", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development", | ||
"DOTNET_ENVIRONMENT": "Development", | ||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19169", | ||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20292" | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning", | ||
"Aspire.Hosting.Dcp": "Warning" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<IsAspireSharedProject>true</IsAspireSharedProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<FrameworkReference Include="Microsoft.AspNetCore.App" /> | ||
|
||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.3.0" /> | ||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" Version="8.0.0-preview.7.24251.11" /> | ||
IEvangelist marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.1" /> | ||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.1" /> | ||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.8.1" /> | ||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.8.1" /> | ||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.8.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Uh oh!
There was an error while loading. Please reload this page.