.NET

Dapr offers NuGet packages to help with the development of .NET pluggable components.

Prerequisites

Note

Development of Dapr pluggable components on Windows requires WSL as some development platforms do not fully support Unix Domain Sockets on “native” Windows.

Project creation

Creating a pluggable component starts with an empty ASP.NET project.

  1. dotnet new web --name <project name>

Add NuGet packages

Add the Dapr .NET pluggable components NuGet package.

  1. dotnet add package Dapr.PluggableComponents.AspNetCore

Create application and service

Creating a Dapr pluggable component application is similar to creating an ASP.NET application. In Program.cs, replace the WebApplication related code with the Dapr DaprPluggableComponentsApplication equivalent.

  1. using Dapr.PluggableComponents;
  2. var app = DaprPluggableComponentsApplication.Create();
  3. app.RegisterService(
  4. "<socket name>",
  5. serviceBuilder =>
  6. {
  7. // Register one or more components with this service.
  8. });
  9. app.Run();

This creates an application with a single service. Each service:

  • Corresponds to a single Unix Domain Socket
  • Can host one or more component types

Note

Only a single component of each type can be registered with an individual service. However, multiple components of the same type can be spread across multiple services.

Implement and register components

Test components locally

Pluggable components can be tested by starting the application on the command line and configuring a Dapr sidecar to use it.

To start the component, in the application directory:

  1. dotnet run

To configure Dapr to use the component, in the resources path directory:

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Component
  3. metadata:
  4. name: <component name>
  5. spec:
  6. type: state.<socket name>
  7. version: v1
  8. metadata:
  9. - name: key1
  10. value: value1
  11. - name: key2
  12. value: value2

Any metadata properties will be passed to the component via its IPluggableComponent.InitAsync() method when the component is instantiated.

To start Dapr (and, optionally, the service making use of the service):

  1. dapr run --app-id <app id> --resources-path <resources path> ...

At this point, the Dapr sidecar will have started and connected via Unix Domain Socket to the component. You can then interact with the component either:

  • Through the service using the component (if started), or
  • By using the Dapr HTTP or gRPC API directly

Create Container

There are several ways to create a container for your component for eventual deployment.

Use .NET SDK

The .NET 7 and later SDKs enable you to create a .NET-based container for your application without a Dockerfile, even for those targeting earlier versions of the .NET SDK. This is probably the simplest way of generating a container for your component today.

Note

Currently, the .NET 7 SDK requires Docker Desktop on the local machine, a special NuGet package, and Docker Desktop on the local machine to build containers. Future versions of .NET SDK plan to eliminate those requirements.

Multiple versions of the .NET SDK can be installed on the local machine at the same time.

Add the Microsoft.NET.Build.Containers NuGet package to the component project.

  1. dotnet add package Microsoft.NET.Build.Containers

Publish the application as a container:

  1. dotnet publish --os linux --arch x64 /t:PublishContainer -c Release

Note

Ensure the architecture argument --arch x64 matches that of the component’s ultimate deployment target. By default, the architecture of the generated container matches that of the local machine. For example, if the local machine is ARM64-based (for example, a M1 or M2 Mac) and the argument is omitted, an ARM64 container will be generated which may not be compatible with deployment targets expecting an AMD64 container.

For more configuration options, such as controlling the container name, tag, and base image, see the .NET publish as container guide.

Use a Dockerfile

While there are tools that can generate a Dockerfile for a .NET application, the .NET SDK itself does not. A typical Dockerfile might look like:

  1. FROM mcr.microsoft.com/dotnet/aspnet:<runtime> AS base
  2. WORKDIR /app
  3. # Creates a non-root user with an explicit UID and adds permission to access the /app folder
  4. # For more info, please refer to https://aka.ms/vscode-docker-dotnet-configure-containers
  5. RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
  6. USER appuser
  7. FROM mcr.microsoft.com/dotnet/sdk:<runtime> AS build
  8. WORKDIR /src
  9. COPY ["<application>.csproj", "<application folder>/"]
  10. RUN dotnet restore "<application folder>/<application>.csproj"
  11. COPY . .
  12. WORKDIR "/src/<application folder>"
  13. RUN dotnet build "<application>.csproj" -c Release -o /app/build
  14. FROM build AS publish
  15. RUN dotnet publish "<application>.csproj" -c Release -o /app/publish /p:UseAppHost=false
  16. FROM base AS final
  17. WORKDIR /app
  18. COPY --from=publish /app/publish .
  19. ENTRYPOINT ["dotnet", "<application>.dll"]

Build the image:

  1. docker build -f Dockerfile -t <image name>:<tag> .

Note

Paths for COPY operations in the Dockerfile are relative to the Docker context passed when building the image, while the Docker context itself will vary depending on the needs of the project being built (for example, if it has referenced projects). In the example above, the assumption is that the Docker context is the component project directory.