This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
Developing applications with the Dapr .NET SDK
Learn about local development integration options for .NET Dapr applications
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 general, 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. These articles are ordered from lowest investment to highest investment. You may want to read them all to get an overview of your options.
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 .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.
Prerequisites
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 a project that’ll serve as our Dapr application. From the same directory, use the following
to create an empty ASP.NET Core project called MyApp
. This will be created relative to your current directory in
MyApp\MyApp.csproj
.
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 MyApp
project so we can reference it during the registration process.
cd aspiredemo.AppHost
dotnet add package CommunityToolkit.Aspire.Hosting.Dapr
dotnet add reference ../MyApp/
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 myApp = builder
.AddProject<Projects.MyApp>("myapp")
.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 = "my-other-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.MyOtherApp>("myotherapp")
.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.
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.
3 - Dapr .NET SDK Development with Project Tye
Learn about local development with Project Tye
Project Tye
.NET Project Tye is a microservices development tool designed to make running many .NET services easy. Tye enables you to store a configuration of multiple .NET services, processes, and container images as a runnable application.
Tye is advantageous for a .NET Dapr developer because:
- Tye has the ability to automate the dapr CLI built-in
- Tye understands .NET’s conventions and requires almost no configuration for .NET services
- Tye can manage the lifetime of your dependencies in containers
Pros/cons:
- Pro: Tye can automate all of the steps described above. You no longer need to think about concepts like ports or app-ids.
- Pro: Since Tye can also manage containers for you, you can make those part of the application definition and stop the long-running containers on your machine.
Using Tye
Follow the Tye Getting Started to install the tye
CLI and create a tye.yaml
for your application.
Next follow the steps in the Tye Dapr recipe to add Dapr. Make sure to specify the relative path to your components folder with components-path
in tye.yaml
.
Next add any additional container dependencies and add component definitions to the folder you created earlier.
You should end up with something like this:
name: store-application
extensions:
# Configuration for dapr goes here.
- name: dapr
components-path: <components-path>
# Services to run go here.
services:
# The name will be used as the app-id. For a .NET project, Tye only needs the path to the project file.
- name: orders
project: orders/orders.csproj
- name: products
project: products/products.csproj
- name: store
project: store/store.csproj
# Containers you want to run need an image name and set of ports to expose.
- name: redis
image: redis
bindings:
- port: 6973
Checkin tye.yaml
in source control with the application code.
You can now use tye run
to launch the whole application from one terminal. When running, Tye has a dashboard at http://localhost:8000
to view application status and logs.
Next steps
Tye runs your services locally as normal .NET process. If you need to debug, then use the attach feature of your debugger to attach to one of the running processes. Since Tye is .NET aware, it has the ability to start a process suspended for startup debugging.
Tye also has an option to run your services in containers if you wish to test locally in containers.
4 - 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.