Sarıkaya Dev Logo

Leveraging Dapr with .NET 8 Minimal APIs for Polyglot Microservices and Distributed Tracing

Mahmut Sarıkaya 4 min read 3 Views 0
Leveraging Dapr with .NET 8 Minimal APIs for Polyglot Microservices and Distributed Tracing

Why Dapr Matters for Modern .NET 8 Microservices

Ever wondered why 70% of new cloud‑native projects choose a sidecar architecture? Dapr (Distributed Application Runtime) abstracts common building blocks—state, pub/sub, bindings—so developers can focus on business logic instead of infrastructure glue. When paired with .NET 8 Minimal APIs, the result is a lean HTTP surface that starts in seconds, yet scales to thousands of instances without code changes.

Setting Up the Development Environment

Before writing code, confirm the following prerequisites: Windows 10 22H2 or Ubuntu 22.04, Docker 20.10+, .NET 8 SDK (8.0.100 or later), and the Dapr CLI (v1.12). Install the CLI with a single command:

daprd init --runtime-version 1.12
Initialize a new solution using dotnet new web -n WeatherApi, then add the Dapr client package:
dotnet add package Dapr.Client
. This setup ensures that the local Dapr sidecar can be launched alongside the Minimal API during debugging.

Creating a Minimal API with Dapr Sidecar

The core of a polyglot microservice is a tiny HTTP endpoint that delegates heavy lifting to other services via Dapr. Below is a complete Program.cs that registers the Dapr client, defines a GET endpoint, and subscribes to a pub/sub topic named weather-updates. The sidecar handles service discovery, so the code calls weather-service by logical name.

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Dapr.Client;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprClient();
var app = builder.Build();

app.MapGet("/weather", async (DaprClient dapr) =>
{
    var forecast = await dapr.InvokeMethodAsync<WeatherForecast[]>(
        HttpMethod.Get, "weather-service", "forecast");
    return Results.Ok(forecast);
}).WithTopic("pubsub", "weather-updates");

app.Run();

Run the service locally with dotnet run and start the sidecar in another terminal:

dapr run --app-id weather-api --app-port 5080 -- dotnet run
. The endpoint is instantly reachable at http://localhost:5080/weather.

Implementing Polyglot Communication

Dapr’s HTTP or gRPC APIs are language‑agnostic. A Node.js service can publish a message to the same pubsub component, and the .NET API will receive it without any extra code. For example, a Python worker might use requests.post("http://localhost:3500/v1.0/publish/pubsub/weather-updates", json=payload). Because the Minimal API subscribes with .WithTopic, Dapr routes the message automatically, enabling a true polyglot ecosystem.

Enabling Distributed Tracing with OpenTelemetry

Observability is non‑negotiable in a distributed system. Dapr emits trace data compatible with OpenTelemetry, so adding a tracer to the Minimal API costs only a few lines. The snippet below configures Jaeger as the trace backend and includes Dapr instrumentation.

builder.Services.AddOpenTelemetry()
    .WithTracing(tracerProviderBuilder =>
    {
        tracerProviderBuilder
            .AddAspNetCoreInstrumentation()
            .AddDaprInstrumentation()
            .AddJaegerExporter(opts =>
            {
                opts.AgentHost = "jaeger"; 
                opts.AgentPort = 6831;
            });
    });

When the API runs inside Kubernetes, the Jaeger collector aggregates spans from every microservice and sidecar, producing a single view of request latency across language boundaries.

Deploying to Kubernetes with Dapr

Containerizing the Minimal API is straightforward:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
COPY bin/Release/net8.0/publish/ .
ENTRYPOINT ["dotnet", "WeatherApi.dll"]
Apply a Dapr annotation to the deployment manifest so the sidecar is injected automatically:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: weather-api
spec:
  replicas: 3
  template:
    metadata:
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "weather-api"
        dapr.io/app-port: "80"
    spec:
      containers:
      - name: weather-api
        image: myregistry/weather-api:latest
        ports:
        - containerPort: 80

Kubernetes schedules the Dapr sidecar alongside each pod, guaranteeing service discovery and tracing without extra configuration.

Best Practices and Pitfalls

1. Keep the Minimal API stateless; rely on Dapr state stores (Redis, Cosmos DB) for persistence.
2. Prefer gRPC for high‑throughput scenarios; the client call changes only the transport string.
3. Guard against version skew: Dapr CLI and sidecar version must match the SDK used in the .NET project.
4. Monitor sidecar health via /v1.0/healthz endpoint; a failing sidecar will silently drop pub/sub messages.
5. Use explicit component names (e.g., pubsub, statestore) to avoid accidental cross‑talk in large clusters.

Sources

• Dapr official documentation (dapr.io)
• Microsoft Docs – .NET 8 Minimal APIs
• OpenTelemetry .NET guide

Author: Mahmut Sarıkaya — sarikayadev.com

Tags: #Dapr #.NET 8 #Minimal APIs #microservices #distributed tracing
Share:
M

Written by

Mahmut Sarıkaya

Software Developer

Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment

3 + 7 =