Voy a ser quirúrgico con esta demo

Quiero que veáis de forma clara y directa las diferencias fundamentales entre usar Dapr de forma tradicional —basado en archivos YAML, configuración externa y acoplamiento manual— y la nueva experiencia con .NET Aspire, que ofrece una integración fluida, tipada y mucho más productiva para trabajar con Dapr en entornos de desarrollo modernos.

Enfoque Tradicional de Dapr (.NET + Dapr + Docker)

1. components/pubsub.yaml (YAML para Dapr)

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: mypubsub
  namespace: default
spec:
  type: pubsub.azure.eventhubs
  version: v1
  metadata:
  - name: connectionString
    secretKeyRef:
      name: eventhub-conn
  - name: eventHubName
    value: mytopic
  - name: consumerGroup
    value: $Default
auth:
  secretStore: env-secretstore

2. Docker Compose con sidecar Dapr

services:
  myapp:
    image: myapp:latest
    ports:
      - "5000:80"
    depends_on:
      - redis
    labels:
      dapr.enable: "true"
      dapr.app-id: "myapp"
      dapr.app-port: "80"
      dapr.components-path: "./components"

Enfoque Moderno (.NET Aspire + Dapr)

1. AppHost.cs con configuración fluida

var builder = DistributedApplication.CreateBuilder(args);

var eventHub = builder.AddAzureEventHubs("eventhub", 
    connectionString: builder.Configuration["EventHubConnectionString"],
    eventHubName: "mytopic",
    consumerGroup: "$Default");

var dapr = builder.AddDapr();

var myApp = builder.AddProject<Projects.MyApp>("myapp")
                   .WithDaprSidecar(dapr)
                   .WithDaprPubSub("mypubsub", eventHub);

builder.Build().Run();

2. Appsettings o Secrets

{
  "EventHubConnectionString": "Endpoint=sb://...;SharedAccessKey=..."
}

Comparativa

Building block: PubSub

Elemento YAML Tradicional Aspire (C# fluido)
Componente Pub/Sub components/pubsub.yaml builder.AddAzureEventHubs(...)
Secretos secretKeyRef y secretStore en YAML En appsettings.json, User Secrets o Azure
Declaración de sidecar Etiquetas en docker-compose.yml WithDaprSidecar()
Asociación app-pubsub Implícita en código o bindings WithDaprPubSub()
Tipado / validación Ninguno Sí, gracias al compilador y Fluent API
Depuración Solo el microservicio ejecutado en ese momento Todos los microservicios implicados

Arquitectura y Componentes

Característica Enfoque Tradicional (.NET 6 + Dapr + Docker) Enfoque Moderno (.NET Aspire + Dapr)
Orquestación de microservicios Manual (docker-compose, scripts) Automática con Aspire.Orchestration
Detección de servicios Basada en configuración o Dapr sidecar discovery Integración nativa con Aspire Service Discovery
Configuración de componentes Dapr Archivos YAML en carpetas locales Declaración fluida en código C# con AppHostBuilder
Comunicación entre servicios gRPC, HTTP con Dapr SDK o directamente Igual, pero con soporte nativo desde Aspire.Dapr

Experiencia de Desarrollo

Característica Enfoque Tradicional Enfoque con .NET Aspire
Configuración inicial Múltiples pasos: Dockerfiles, YAMLs, Compose Un único punto de entrada: AppHost.cs + Aspire Dashboard
Visibilidad del sistema Docker CLI, logs, manual Dashboard web con estado en tiempo real y dependencias
Mocking de servicios externos Difícil, se requiere infraestructura local simulada Sencillo con Aspire.Hosting.Testing y entornos integrados
Onboarding de nuevos devs Lento: requiere entender Docker, Compose, Dapr YAMLs Rápido: dotnet run sobre Aspire y todo funciona

Despliegue y Entornos

Característica Enfoque Tradicional Enfoque con .NET Aspire
Paridad local-producción Puede variar según Compose vs K8s Mejor controlada, pero aún limitada si no se usa K8s
Multi-entorno Manual (docker-compose.override, etc.) Más flexible con perfiles de entorno en Aspire
Contenedores Necesario configurar Dockerfiles y Compose Opcional en local, Aspire puede orquestar sin Docker

Observabilidad y Depuración

Característica Enfoque Tradicional Enfoque con .NET Aspire
Logs, tracing, métricas A configurar: OpenTelemetry, Zipkin, Prometheus Integración automática con OpenTelemetry, logging estructurado
Diagnóstico en desarrollo Logs de Docker, terminales múltiples Dashboard visual, seguimiento de servicios, métricas, tracing
Debug interactivo Más complejo en apps distribuidas Simplificado con orquestación local de procesos y VS tooling

Productividad del Equipo

Característica Enfoque Tradicional Enfoque con .NET Aspire
Tiempo de arranque del sistema Lento (pull de imágenes, Dapr init, Compose up) Muy rápido: dotnet run orquesta todo en local
Cohesión entre microservicios Independiente, cada microservicio aislado Alta: solución unificada, configuración centralizada
Experiencia de onboarding Requiere guía extensa y configuración manual Rápida y estandarizada con Aspire templates

Conclusión

La evolución de Dapr junto a .NET Aspire marca un cambio significativo en cómo desarrollamos y operamos aplicaciones distribuidas. Mientras que el enfoque tradicional sigue siendo válido y potente, Aspire lleva la experiencia un paso más allá, reduciendo la complejidad operativa, centralizando la configuración y mejorando drásticamente la productividad y la experiencia de desarrollo.

Aspire no solo simplifica el onboarding y la depuración, sino que convierte la construcción de soluciones distribuidas en un proceso más natural, guiado y coherente con el ecosistema .NET.

¿Cuál deberías usar?

  • Si estás manteniendo una solución existente con infraestructura ya definida en Docker, Kubernetes y Dapr clásico, o necesitas un control muy fino sobre cada parte del stack, el enfoque tradicional sigue siendo sólido.

  • Pero si estás empezando un nuevo proyecto, quieres acelerar el desarrollo, reducir la curva de entrada para nuevos desarrolladores y aprovechar lo último del stack .NET, .NET Aspire con Dapr es claramente la mejor elección. Te ofrece una orquestación moderna, configuración fluida, visibilidad completa del sistema y un entorno de desarrollo mucho más amigable.

En resumen: el enfoque tradicional funciona, pero Aspire es futuro. Y ya está aquí.

Enlaces de interés