Developing applications with the Dapr .NET SDK
Deployment integrations with the Dapr .NET SDK
Thinking more than one at a time
Using your favorite IDE or editor to launch an application typically assumes that you only need to run one thing:
the application you’re debugging. However, developing microservices challenges you to think about your local
development process for more than one at a time. A microservices application has multiple services that you might
need running simultaneously, and dependencies (like state stores) to manage.
Adding Dapr to your development process means you need to manage the following concerns:
- Each service you want to run
- A Dapr sidecar for each service
- Dapr component and configuration manifests
- Additional dependencies such as state stores
- optional: the Dapr placement service for actors
This document assumes that you’re building a production application and want to create a repeatable and robust set of
development practices. The guidance here is generalized, and applies to any .NET server application using
Dapr (including actors).
Managing components
You have two primary methods of storing component definitions for local development with Dapr:
- Use the default location (
~/.dapr/components
) - Use your own location
Creating a folder within your source code repository to store components and configuration will give you a way to
version and share these definitions. The guidance provided here will assume you created a folder next to the
application source code to store these files.
Development options
Choose one of these links to learn about tools you can use in local development scenarios. It’s suggested that
you familiarize yourself with each of them to get a sense of the options provided by the .NET SDK.
1 - Dapr .NET SDK Development with Dapr CLI
Learn about local development with the Dapr CLI
Dapr CLI
Consider this to be a .NET companion to the Dapr Self-Hosted with Docker Guide.
The Dapr CLI provides you with a good base to work from by initializing a local redis container, zipkin container, the placement service, and component manifests for redis. This will enable you to work with the following building blocks on a fresh install with no additional setup:
You can run .NET services with dapr run
as your strategy for developing locally. Plan on running one of these commands per-service in order to launch your application.
- Pro: this is easy to set up since its part of the default Dapr installation
- Con: this uses long-running docker containers on your machine, which might not be desirable
- Con: the scalability of this approach is poor since it requires running a separate command per-service
Using the Dapr CLI
For each service you need to choose:
- A unique app-id for addressing (
app-id
) - A unique listening port for HTTP (
port
)
You also should have decided on where you are storing components (components-path
).
The following command can be run from multiple terminals to launch each service, with the respective values substituted.
dapr run --app-id <app-id> --app-port <port> --components-path <components-path> -- dotnet run -p <project> --urls http://localhost:<port>
Explanation: this command will use dapr run
to launch each service and its sidecar. The first half of the command (before --
) passes required configuration to the Dapr CLI. The second half of the command (after --
) passes required configuration to the dotnet run
command.
đĄ Ports
Since you need to configure a unique port for each service, you can use this command to pass that port value to both Dapr and the service. --urls http://localhost:<port>
will configure ASP.NET Core to listen for traffic on the provided port. Using configuration at the commandline is a more flexible approach than hardcoding a listening port elsewhere.If any of your services do not accept HTTP traffic, then modify the command above by removing the --app-port
and --urls
arguments.
Next steps
If you need to debug, then use the attach feature of your debugger to attach to one of the running processes.
If you want to scale up this approach, then consider building a script which automates this process for your whole application.
2 - Dapr .NET SDK Development with Docker-Compose
Learn about local development with Docker-Compose
Docker-Compose
Consider this to be a .NET companion to the Dapr Self-Hosted with Docker Guide.
docker-compose
is a CLI tool included with Docker Desktop that you can use to run multiple containers at a time. It is a way to automate the lifecycle of multiple containers together, and offers a development experience similar to a production environment for applications targeting Kubernetes.
- Pro: Since
docker-compose
manages containers for you, you can make dependencies part of the application definition and stop the long-running containers on your machine. - Con: most investment required, services need to be containerized to get started.
- Con: can be difficult to debug and troubleshoot if you are unfamilar with Docker.
Using docker-compose
From the .NET perspective, there is no specialized guidance needed for docker-compose
with Dapr. docker-compose
runs containers, and once your service is in a container, configuring it similar to any other programming technology.
đĄ App Port
In a container, an ASP.NET Core app will listen on port 80 by default. Remember this for when you need to configure the --app-port
later.To summarize the approach:
- Create a
Dockerfile
for each service - Create a
docker-compose.yaml
and place check it in to the source code repository
To understand the authoring the docker-compose.yaml
you should start with the Hello, docker-compose sample.
Similar to running locally with dapr run
for each service you need to choose a unique app-id. Choosing the container name as the app-id will make this simple to remember.
The compose file will contain at a minimum:
- A network that the containers use to communicate
- Each service’s container
- A
<service>-daprd
sidecar container with the service’s port and app-id specified - Additional dependencies that run in containers (redis for example)
- optional: Dapr placement container (for actors)
You can also view a larger example from the eShopOnContainers sample application.
3 - Dapr .NET SDK Development with .NET Aspire
Learn about local development with .NET Aspire
.NET Aspire
.NET Aspire is a development tool
designed to make it easier to include external software into .NET applications by providing a framework that allows
third-party services to be readily integrated, observed and provisioned alongside your own software.
Aspire simplifies local development by providing rich integration with popular IDEs including
Microsoft Visual Studio,
Visual Studio Code,
JetBrains Rider and others
to launch your application with the debugger while automatically launching and provisioning access to other
integrations as well, including Dapr.
While Aspire also assists with deployment of your application to various cloud hosts like Microsoft Azure and
Amazon AWS, deployment is currently outside the scope of this guide. More information can be found in Aspire’s
documentation here.
An end-to-end demonstration featuring the following and demonstrating service invocation between multiple Dapr-enabled
services can be found here.
Prerequisites
- Both the Dapr .NET SDK and .NET Aspire are compatible with .NET 8
or .NET 9
- An OCI compliant container runtime such as Docker Desktop or
Podman
- Install and initialize Dapr v1.16 or later
Using .NET Aspire via CLI
We’ll start by creating a brand new .NET application. Open your preferred CLI and navigate to the directory you wish
to create your new .NET solution within. Start by using the following command to install a template that will create
an empty Aspire application:
dotnet new install Aspire.ProjectTemplates
Once that’s installed, proceed to create an empty .NET Aspire application in your current directory. The -n
argument
allows you to specify the name of the output solution. If it’s excluded, the .NET CLI will instead use the name
of the output directory, e.g. C:\source\aspiredemo
will result in the solution being named aspiredemo
. The rest
of this tutorial will assume a solution named aspiredemo
.
dotnet new aspire -n aspiredemo
This will create two Aspire-specific directories and one file in your directory:
aspiredemo.AppHost/
contains the Aspire orchestration project that is used to configure each of the integrations
used in your application(s).aspiredemo.ServiceDefaults/
contains a collection of extensions meant to be shared across your solution to aid in
resilience, service discovery and telemetry capabilities offered by Aspire (these are distinct from the capabilities
offered in Dapr itself).aspiredemo.sln
is the file that maintains the layout of your current solution
We’ll next create twp projects that’ll serve as our Dapr application and demonstrate Dapr functionality. From the same
directory, use the following to create an empty ASP.NET Core project called FrontEndApp
and another called
‘BackEndApp’. Either one will be created relative to your current directory in
FrontEndApp\FrontEndApp.csproj
and BackEndApp\BackEndApp.csproj
, respectively.
dotnet new web --name FrontEndApp
Next we’ll configure the AppHost project to add the necessary package to support local Dapr development. Navigate
into the AppHost directory with the following and install the CommunityToolkit.Aspire.Hosting.Dapr
package from NuGet into the project.
We’ll also add a reference to our FrontEndApp
project so we can reference it during the registration process.
cd aspiredemo.AppHost
dotnet add package CommunityToolkit.Aspire.Hosting.Dapr
dotnet add reference ../FrontEndApp/
dotnet add reference ../BackEndApp/
Next, we need to configure Dapr as a resource to be loaded alongside your project. Open the Program.cs
file in that
project within your preferred IDE. It should look similar to the following:
var builder = DistributedApplication.CreateBuilder(args);
builder.Build().Run();
If you’re familiar with the dependency injection approach used in ASP.NET Core projects or others utilizing the
Microsoft.Extensions.DependencyInjection
functionality, you’ll find that this will be a familiar experience.
Because we’ve already added a project reference to MyApp
, we need to start by adding a reference in this configuration
as well. Add the following before the builder.Build().Run()
line:
var backEndApp = builder
.AddProject<Projects.BackEndApp>("be")
.WithDaprSidecar();
var frontEndApp = builder
.AddProject<Projects.FrontEndApp>("fe")
.WithDaprSidecar();
Because the project reference has been added to this solution, your project shows up as a type within the Projects.
namespace for our purposes here. The name of the variable you assign the project to doesn’t much matter in this tutorial
but would be used if you wanted to create a reference between this project and another using Aspire’s service discovery
functionality.
Adding .WithDaprSidecar()
configures Dapr as a .NET Aspire resource so that when the project runs, the sidecar will be
deployed alongside your application. This accepts a number of different options and could optionally be configured as in
the following example:
DaprSidecarOptions sidecarOptions = new()
{
AppId = "how-dapr-identifies-your-app",
AppPort = 8080, //Note that this argument is required if you intend to configure pubsub, actors or workflows as of Aspire v9.0
DaprGrpcPort = 50001,
DaprHttpPort = 3500,
MetricsPort = 9090
};
builder
.AddProject<Projects.BackEndApp>("be")
.WithReference(myApp)
.WithDaprSidecar(sidecarOptions);
As indicated in the example above, as of .NET Aspire 9.0, if you intend to use any functionality in which Dapr needs to
call into your application such as pubsub, actors or workflows, you will need to specify your AppPort as
a configured option as Aspire will not automatically pass it to Dapr at runtime. It’s expected that this behavior will
change in a future release as a fix has been merged and can be tracked
here.
Finally, let’s add an endpoint to the back-end app that we can invoke using Dapr’s service invocation to display to a
page to demonstrate that Dapr is working as expected.
When you open the solution in your IDE, ensure that the aspiredemo.AppHost
is configured as your startup project, but
when you launch it in a debug configuration, you’ll note that your integrated console should reflect your expected Dapr
logs and it will be available to your application.