.NET Development

.NET Developer-Plattformen im Vergleich: ASP.NET Core, ABP, PlatformPlatform & Aspire

Eine technische Analyse für moderne .NET Entwickler - Was bietet ASP.NET Core out-of-the-box? Wann brauchen Sie ABP Framework, PlatformPlatform oder .NET Aspire? Produktivität vs. Lock-in-Effekte im Detail.

📖 18 Min. Lesezeit
ASP.NET Core ABP Framework PlatformPlatform .NET Aspire Developer-Plattformen DDD CQRS

.NET Developer-Plattformen im Vergleich: Wann brauchen Sie mehr als ASP.NET Core?

Als .NET Entwickler stehen Sie heute vor einer interessanten Entscheidung: ASP.NET Core bietet bereits enorm viel out-of-the-box. Aber wann lohnt sich eine Developer-Plattform wie ABP Framework, PlatformPlatform oder .NET Aspire?

Diese Frage beschäftigt mich seit Jahren - sowohl als CTO, der Architektur-Entscheidungen treffen muss, als auch als Entwickler, der produktiv sein will ohne in Boilerplate-Code zu ertrinken.

In diesem Artikel analysiere ich:

  • Was ASP.NET Core bereits mitbringt (und oft unterschätzt wird)
  • Was die drei führenden .NET Developer-Plattformen zusätzlich bieten
  • Wann Sie welche Plattform wählen sollten
  • Die Trade-offs: Produktivität vs. Lock-in-Effekte

ASP.NET Core out-of-the-box: Mehr als Sie denken

Bevor wir über Plattformen sprechen: ASP.NET Core ist bereits erstaunlich feature-reich. Viele Entwickler wissen nicht, was sie mit minimalen Dependencies bekommen.

1. Logging: Strukturiert und erweiterbar

Out-of-the-box seit .NET 6:

var builder = WebApplication.CreateBuilder(args);

// Logging ist bereits konfiguriert!
var app = builder.Build();

app.MapGet("/api/users/{id}", (int id, ILogger<Program> logger) =>
{
    logger.LogInformation("Fetching user {UserId}", id);
    // ...
    return Results.Ok(user);
});

Was Sie bekommen:

  • Strukturiertes Logging (nicht nur Strings, sondern Key-Value-Pairs)
  • Log-Levels (Trace, Debug, Information, Warning, Error, Critical)
  • Scopes für Kontext (automatisch bei HTTP-Requests)
  • Providers: Console, Debug, EventSource (Windows), EventLog (Windows)

Mit einem NuGet-Paket erweitern:

dotnet add package Serilog.AspNetCore
builder.Host.UseSerilog((context, config) =>
{
    config
        .WriteTo.Console()
        .WriteTo.File("logs/app-.txt", rollingInterval: RollingInterval.Day)
        .WriteTo.Seq("http://localhost:5341"); // Zentrales Logging
});

Ergebnis: Production-ready Logging mit 3 Zeilen Code.

2. Authentifizierung & Authorization: Identity + JWT

ASP.NET Core Identity out-of-the-box:

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
// Startup
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

// Usage
app.MapPost("/api/auth/register", async (
    UserManager<ApplicationUser> userManager,
    RegisterRequest request) =>
{
    var user = new ApplicationUser { UserName = request.Email, Email = request.Email };
    var result = await userManager.CreateAsync(user, request.Password);

    return result.Succeeded
        ? Results.Ok()
        : Results.BadRequest(result.Errors);
});

Was Sie bekommen:

  • Password-Hashing (PBKDF2, sicher by default)
  • User-Management (Create, Update, Delete, Find)
  • Role-Based-Authorization (Roles, Claims, Policies)
  • Two-Factor-Authentication (TOTP, Email, SMS)
  • Account-Lockout (nach X fehlgeschlagenen Logins)
  • Email-Confirmation & Password-Reset

JWT-Authentication mit einem NuGet-Paket:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "your-issuer",
            ValidAudience = "your-audience",
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes("your-secret-key"))
        };
    });

// Protected endpoint
app.MapGet("/api/protected", [Authorize] () => "Secret data");

Ergebnis: Production-ready JWT-Auth mit 10-15 Zeilen Code.

3. Dependency Injection: Built-in und mächtig

Keine externen Packages nötig:

// Register
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddSingleton<ICacheService, RedisCacheService>();
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();

// Usage (automatisch injected)
app.MapGet("/api/users", (IUserService userService) =>
    userService.GetAllAsync());

Lifetimes:

  • Singleton: Eine Instanz für gesamte App-Lifetime
  • Scoped: Eine Instanz pro HTTP-Request
  • Transient: Neue Instanz bei jedem Inject

Advanced: Keyed Services (.NET 8+):

builder.Services.AddKeyedScoped<IPaymentProvider, StripeProvider>("stripe");
builder.Services.AddKeyedScoped<IPaymentProvider, PayPalProvider>("paypal");

app.MapPost("/api/payment", (
    [FromKeyedServices("stripe")] IPaymentProvider provider,
    PaymentRequest request) =>
{
    return provider.ProcessAsync(request);
});

4. Configuration: Flexible und typsicher

Appsettings.json + Environment Variables + User Secrets:

// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MyDb;..."
  },
  "JwtSettings": {
    "Secret": "your-secret-key",
    "ExpirationMinutes": 60
  }
}
// Typsichere Configuration
public class JwtSettings
{
    public string Secret { get; set; }
    public int ExpirationMinutes { get; set; }
}

builder.Services.Configure<JwtSettings>(
    builder.Configuration.GetSection("JwtSettings"));

// Usage
app.MapGet("/api/config", (IOptions<JwtSettings> settings) =>
{
    return settings.Value.ExpirationMinutes;
});

User Secrets (für Entwicklung, keine Secrets in Git):

dotnet user-secrets init
dotnet user-secrets set "JwtSettings:Secret" "dev-secret-123"

5. Weitere out-of-the-box Features

Health Checks:

builder.Services.AddHealthChecks()
    .AddSqlServer(connectionString)
    .AddRedis(redisConnection);

app.MapHealthChecks("/health");

CORS:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("https://frontend.com")
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

Rate Limiting (.NET 7+):

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("fixed", limiterOptions =>
    {
        limiterOptions.PermitLimit = 100;
        limiterOptions.Window = TimeSpan.FromMinutes(1);
    });
});

app.MapGet("/api/limited", [EnableRateLimiting("fixed")] () => "Rate limited");

Output Caching (.NET 7+):

builder.Services.AddOutputCache();

app.MapGet("/api/products", [OutputCache(Duration = 60)] () => GetProducts());

Zwischenfazit: ASP.NET Core ist bereits mächtig

Mit ASP.NET Core + 3-5 NuGet-Paketen bekommen Sie:

  • ✅ Strukturiertes Logging (Serilog)
  • ✅ Authentifizierung & Authorization (Identity + JWT)
  • ✅ Dependency Injection (built-in)
  • ✅ Configuration-Management (built-in)
  • ✅ Health Checks, CORS, Rate Limiting, Caching

Für viele Projekte reicht das völlig.

Aber: Es gibt Bereiche, wo ASP.NET Core bewusst keine Meinung hat:

  • Architektur-Pattern: Wie strukturieren Sie Ihren Code? (Layered, Clean, DDD?)
  • Cross-Cutting-Concerns: Wie implementieren Sie Audit-Logging, Validation, Exception-Handling konsistent?
  • Multi-Tenancy: Wie bauen Sie SaaS mit Tenant-Isolation?
  • Microservices-Orchestrierung: Wie entwickeln Sie lokal mit 10+ Services?
  • Boilerplate-Reduktion: Wie vermeiden Sie repetitive CRUD-Code?

Hier kommen Developer-Plattformen ins Spiel.

Plattform 1: ABP Framework - Das Enterprise-Schweizer-Taschenmesser

Repository: github.com/abpframework/abp Stars: 13.9k ⭐ | License: LGPL-3.0 (Open-Source) + Commercial Zielgruppe: Enterprise-Anwendungen, SaaS-Produkte, komplexe Business-Logic

Was ist ABP?

ABP ist ein vollwertiges Application Framework für ASP.NET Core, das auf Domain-Driven Design (DDD) basiert. Es positioniert sich als "Bridge between ASP.NET Core and real-world business application requirements".

Die Vision: Entwickler sollen sich auf Business-Logic konzentrieren, nicht auf Infrastructure-Code.

Architektur-Patterns & Prinzipien

ABP ist hochgradig opinionated und bringt klare Architektur-Vorgaben:

1. Domain-Driven Design (DDD):

MyProject.Application        (Application-Services, DTOs)
MyProject.Domain             (Entities, Domain-Services, Repositories)
MyProject.Domain.Shared      (Enums, Constants)
MyProject.EntityFrameworkCore (EF-Core-Implementierung)
MyProject.HttpApi            (Controllers)
MyProject.HttpApi.Client     (HTTP-Clients für Microservices)

2. Multi-Layered Architecture:

  • Presentation Layer: UI/API
  • Application Layer: Use-Cases, DTOs, Validation
  • Domain Layer: Business-Logic, Entities, Domain-Events
  • Infrastructure Layer: Datenbank, External-Services

3. Modularität: Jedes Feature kann als ABP-Modul strukturiert werden:

[DependsOn(
    typeof(AbpIdentityApplicationModule),
    typeof(AbpAccountApplicationModule)
)]
public class MyProjectApplicationModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        // Modul-spezifische Services
    }
}

Was bietet ABP zusätzlich zu ASP.NET Core?

1. Vorgefertigte Module (Pre-Built Functionality):

ABP liefert Production-Ready-Module, die Sie sofort nutzen können:

Modul Funktionalität
Identity User-Management, Roles, Permissions, Claims
Account Login, Register, Forgot-Password, Email-Confirmation
Tenant Management Multi-Tenancy für SaaS (Tenant-Isolation in DB)
OpenIddict OAuth2/OpenID Connect Server (Token-Issuing)
Audit Logging Automatisches Logging aller Entity-Changes
Feature Management Feature-Toggles pro Tenant
Setting Management Hierarchische Settings (Global, Tenant, User)
Background Jobs Job-Queue mit Retry-Logic (Hangfire/Quartz-Integration)
BLOB Storage Abstraktion für File-Storage (Azure, AWS, Filesystem)

Beispiel: Tenant-Management

// Multi-Tenancy aktivieren
[DependsOn(typeof(AbpTenantManagementApplicationModule))]
public class MyModule : AbpModule { }

// Automatische Tenant-Isolation
public class ProductAppService : ApplicationService
{
    private readonly IRepository<Product> _productRepository;

    public async Task<List<ProductDto>> GetListAsync()
    {
        // ABP filtert automatisch nach aktuellem Tenant!
        var products = await _productRepository.GetListAsync();
        return ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
    }
}

Das Magische: ABP injiziert automatisch ITenantId und filtert alle Queries. Sie schreiben keinen Tenant-spezifischen Code.

2. Cross-Cutting-Concerns: Automatisiert

ABP übernimmt repetitive Aufgaben automatisch:

Validation:

public class CreateProductDto
{
    [Required]
    [StringLength(128)]
    public string Name { get; set; }

    [Range(0, 999999)]
    public decimal Price { get; set; }
}

// Validation passiert automatisch vor Application-Service-Call
public class ProductAppService : ApplicationService
{
    public async Task CreateAsync(CreateProductDto input)
    {
        // Wenn wir hier ankommen, ist input bereits validiert!
    }
}

Authorization:

[Authorize(MyPermissions.Products.Create)]
public async Task CreateAsync(CreateProductDto input)
{
    // Automatischer Permission-Check
}

Audit-Logging:

public class Product : FullAuditedEntity<Guid>
{
    public string Name { get; set; }
    // FullAuditedEntity gibt uns automatisch:
    // - CreationTime, CreatorId
    // - LastModificationTime, LastModifierId
    // - IsDeleted, DeletionTime, DeleterId (Soft-Delete)
}

Unit-of-Work:

public async Task CreateProductAsync(CreateProductDto input)
{
    var product = new Product { Name = input.Name };
    await _productRepository.InsertAsync(product);

    // SaveChanges() wird automatisch am Ende aufgerufen!
    // Bei Exception: automatisches Rollback
}

3. Multi-Tenancy: SaaS-ready

ABP hat drei Multi-Tenancy-Strategien:

// appsettings.json
{
  "AbpMultiTenancy": {
    "IsEnabled": true
  }
}

// Tenant-Resolver (wie wird Tenant identifiziert?)
services.AddAbpMultiTenancy(options =>
{
    options.TenantResolvers.Add(new DomainTenantResolveContributor());
    options.TenantResolvers.Add(new HeaderTenantResolveContributor());
});

Strategien:

  • Shared Database: Alle Tenants in einer DB (+ TenantId-Column)
  • Database per Tenant: Jeder Tenant hat eigene Datenbank
  • Hybrid: Manche Tenants shared, große Tenants dedicated DB

4. Dynamic API & Auto-API-Controllers

ABP generiert automatisch REST-APIs aus Application-Services:

public interface IProductAppService : IApplicationService
{
    Task<PagedResultDto<ProductDto>> GetListAsync(PagedAndSortedResultRequestDto input);
    Task<ProductDto> GetAsync(Guid id);
    Task<ProductDto> CreateAsync(CreateProductDto input);
    Task UpdateAsync(Guid id, UpdateProductDto input);
    Task DeleteAsync(Guid id);
}

// ABP generiert automatisch REST-Endpoints:
// GET    /api/app/product
// GET    /api/app/product/{id}
// POST   /api/app/product
// PUT    /api/app/product/{id}
// DELETE /api/app/product/{id}

Kein Controller-Code nötig!

5. ABP Suite: Code-Generator

ABP Commercial (kostenpflichtig) bietet ABP Suite - einen Code-Generator:

abp suite

Sie definieren ein Entity (z.B. Product):

  • Name, Properties, Relationships
  • Permissions (wer darf lesen/schreiben?)
  • Navigation-Properties

ABP Suite generiert:

  • Domain-Entities
  • Application-Services + DTOs
  • Repositories
  • Unit-Tests
  • Permissions
  • Angular/Blazor/MVC UI

Ergebnis: CRUD für ein Entity in < 5 Minuten.

Wann sollten Sie ABP Framework nutzen?

✅ Perfekt für:

  • Enterprise-Anwendungen mit komplexer Business-Logic (DDD macht Sinn)
  • SaaS-Produkte (Multi-Tenancy out-of-the-box)
  • Teams mit unterschiedlichem Skill-Level (Framework gibt klare Struktur vor)
  • Projekte mit vielen CRUD-Operationen (ABP Suite spart enorm Zeit)
  • Long-Term-Projekte (Wartbarkeit durch klare Architektur)

❌ Weniger geeignet für:

  • Microservices mit vielen kleinen Services (ABP ist pro Service ein Full-Stack-Framework → Overhead)
  • Hochperformante APIs (Abstraktions-Layer haben Performance-Kosten)
  • Prototypen/MVPs (Learning-Curve ist steil für neue Entwickler)
  • Teams, die eigene Architektur bevorzugen (ABP ist sehr opinionated)

Der Trade-off: Produktivität vs. Lock-in

Vorteile:

  • Enorme Produktivität: CRUD in Minuten, nicht Tagen
  • Konsistente Architektur: Alle Entwickler folgen denselben Patterns
  • Production-Ready-Modules: Identity, Tenancy, Audit-Logging funktionieren sofort
  • Aktive Community: 13.9k Stars, 3.6k Forks, aktive Entwicklung

Nachteile:

  • ⚠️ Steile Learning-Curve: DDD, CQRS, Modularität - viel zu lernen
  • ⚠️ Lock-in: Schwer, aus ABP rauszukommen (zu viel Framework-spezifischer Code)
  • ⚠️ Overhead: Viele Abstraktionen → Performance-Impact bei hochperformanten APIs
  • ⚠️ Commercial-Modules: Beste Features (ABP Suite, Chat, Forms) sind kostenpflichtig ($2.5k-$20k/Jahr)

Plattform 2: PlatformPlatform - Der moderne SaaS-Blueprint

Repository: github.com/platformplatform/PlatformPlatform Stars: ~1.5k ⭐ (noch jung) | License: MIT (Open-Source) Zielgruppe: B2B/B2C-SaaS-Startups, Cloud-Native-Projekte

Was ist PlatformPlatform?

PlatformPlatform ist kein Framework, sondern ein Referenz-Projekt - ein vollständiger, produktionsreifer SaaS-Blueprint, den Sie forken und für Ihr Produkt anpassen.

Die Vision: "Zeigen, wie Top-Tier-SaaS-Produkte gebaut werden" - mit modernen Patterns, Security-Best-Practices und DevOps-Automation.

Architektur-Patterns & Prinzipien

PlatformPlatform folgt modernsten Architektur-Trends:

1. Vertical Slice Architecture (nicht Layers!):

Statt horizontaler Layer (Controller, Services, Repositories) organisiert PlatformPlatform nach Features:

/src/Application/
  /AccountManagement/
    /Commands/
      RegisterUser.cs          (Command + Handler + Validation)
      ConfirmEmail.cs
    /Queries/
      GetUserProfile.cs        (Query + Handler)
    /Domain/
      User.cs                  (Entity)
      UserRegisteredEvent.cs   (Domain-Event)

Vorteile:

  • Alles, was zu "User-Registration" gehört, ist in einem Ordner
  • Neue Features = neuer Ordner (kein Ändern von 5 verschiedenen Layern)
  • Leichter zu verstehen für neue Entwickler

2. CQRS (Command-Query-Responsibility-Segregation):

Trennung von Schreib-Operationen (Commands) und Lese-Operationen (Queries):

// Command (schreibt Daten)
public record RegisterUserCommand(string Email, string Password) : ICommand;

public class RegisterUserHandler : ICommandHandler<RegisterUserCommand>
{
    public async Task Handle(RegisterUserCommand command, CancellationToken ct)
    {
        // Validation
        // Create User
        // Publish UserRegisteredEvent
    }
}

// Query (liest Daten, optimiert für Performance)
public record GetUserProfileQuery(Guid UserId) : IQuery<UserProfileDto>;

public class GetUserProfileHandler : IQueryHandler<GetUserProfileQuery, UserProfileDto>
{
    public async Task<UserProfileDto> Handle(GetUserProfileQuery query, CancellationToken ct)
    {
        // Direct SQL für Performance (kein ORM-Overhead)
        return await _db.QuerySingleAsync<UserProfileDto>(
            "SELECT * FROM Users WHERE Id = @Id", new { query.UserId });
    }
}

3. Domain-Driven Design (DDD):

Ähnlich wie ABP, aber pragmatischer:

  • Rich Domain Models (Logik im Entity, nicht in Services)
  • Domain Events (für lose Kopplung)
  • Aggregates (für Transaktions-Grenzen)
public class User : AggregateRoot
{
    public string Email { get; private set; }
    public bool EmailConfirmed { get; private set; }

    // Business-Logic im Entity
    public void ConfirmEmail(string confirmationToken)
    {
        if (EmailConfirmed)
            throw new DomainException("Email already confirmed");

        if (!IsValidToken(confirmationToken))
            throw new DomainException("Invalid confirmation token");

        EmailConfirmed = true;

        // Domain-Event publishen
        RaiseDomainEvent(new UserEmailConfirmedEvent(Id));
    }
}

4. Self-Contained Systems (SCS):

PlatformPlatform ist aktuell ein Monolith, aber strukturiert für zukünftige Microservices:

/src/
  /AccountManagement/     (könnte eigener Service werden)
  /BackOffice/            (könnte eigener Service werden)
  /Shared/                (Shared-Kernel)

Was bietet PlatformPlatform zusätzlich?

1. Production-Ready-SaaS-Features:

Das Projekt ist kein "Hello World" - es ist ein funktionierendes SaaS-Produkt:

  • Account-Management: User-Registration, Email-Confirmation, Password-Reset
  • Tenant-Management: Multi-Tenancy (Subdomain-based: customer1.yourapp.com)
  • Back-Office: Admin-Panel für Support-Team
  • Billing (geplant): Stripe-Integration, Subscription-Management

2. Security-First-Ansatz:

PlatformPlatform hat 100% Security Score in Azure Defender:

  • Keine Secrets im Code: Alles via Azure Key Vault
  • Managed Identities: Services authentifizieren sich ohne Passwords
  • Role-Based-Access-Control (RBAC): Azure AD-Integration
  • Input-Validation: FluentValidation auf allen Commands
  • SQL-Injection-Prevention: Parameterized Queries
  • CSRF-Protection: Anti-Forgery-Tokens

3. DevOps-Automation:

Ein Highlight ist die Developer-Experience:

# Lokale Entwicklung mit .NET Aspire
dotnet run --project src/AppHost

# Öffnet automatisch:
# - Frontend (React Dev-Server)
# - Backend-APIs
# - SQL-Database (in Docker)
# - Developer-Dashboard (Logs, Traces, Metrics)

Deployment zu Azure:

# Einmalig: Azure-Infrastruktur provisionieren
./developer-cli azure provision

# Deploy (via GitHub Actions oder lokal)
./developer-cli azure deploy

Was passiert:

  • Infrastructure-as-Code (Bicep): Azure Container Apps, SQL, Storage, Key Vault
  • CI/CD (GitHub Actions): Build, Test, Deploy automatisch
  • Managed Identities: Keine Secrets in Config-Files
  • Auto-Scaling: Von 0 bis 1M Requests/Tag

Kosten: < $2/Tag für Development, $50-100/Monat für Production (je nach Load)

4. Frontend-Integration:

PlatformPlatform ist nicht nur Backend:

  • React 19 + TypeScript
  • React Aria Components (Accessibility first)
  • TanStack Router (Type-safe Routing)
  • TanStack Query (Data-Fetching mit Caching)

Frontend-Backend-Integration:

// Auto-generated TypeScript Client (aus C# API)
const { data, error, isLoading } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => apiClient.users.getById(userId)
});

5. AI-Assisted Development:

PlatformPlatform hat 30+ AI-Rules für GitHub Copilot/Cursor:

.github/copilot-instructions.md:

When creating a new Command:
- Use record-type
- Inherit from ICommand or ICommand<TResult>
- Create Handler in same file
- Add FluentValidation Validator
- Follow Vertical Slice Architecture

Ergebnis: Copilot generiert Code, der zum Projekt-Stil passt.

Wann sollten Sie PlatformPlatform nutzen?

✅ Perfekt für:

  • SaaS-Startups (B2B oder B2C), die schnell ein MVP bauen wollen
  • Cloud-Native-Projekte (Azure-fokussiert)
  • Teams, die moderne Patterns lernen wollen (Vertical Slice, CQRS, DDD)
  • Projekte mit Security-Anforderungen (Banking, Healthcare, etc.)
  • Developer-Experience-fokussierte Teams (Copilot-Integration, CLI-Tools)

❌ Weniger geeignet für:

  • On-Premise-Deployments (stark Azure-optimiert)
  • Non-SaaS-Projekte (viel SaaS-spezifischer Code, der nicht nötig wäre)
  • Teams, die andere Clouds nutzen (AWS/GCP-Adaption erfordert Arbeit)
  • Enterprise-Projekte mit etablierter Architektur (PlatformPlatform ist opinionated)

Der Trade-off: Modernität vs. Reife

Vorteile:

  • Modernste Patterns: Vertical Slice, CQRS, SCS - State-of-the-Art
  • Production-Ready: Nicht nur Code-Beispiele, sondern funktionierendes SaaS
  • DevOps-First: CI/CD, IaC, Monitoring - alles dabei
  • Security-Best-Practices: 100% Azure-Defender-Score
  • MIT-License: Kostenlos, auch für kommerzielle Nutzung

Nachteile:

  • ⚠️ Jung & Small-Community: ~1.5k Stars, weniger Community-Support als ABP
  • ⚠️ Azure-Lock-in: Stark Azure-optimiert, schwer zu anderen Clouds zu migrieren
  • ⚠️ Learning-Curve: CQRS, Vertical Slice, DDD - nicht für .NET-Anfänger
  • ⚠️ Opinionated: Sie müssen Fork anpassen, nicht "Framework + Ihre App"

Plattform 3: .NET Aspire - Orchestrierung für Cloud-Native-Apps

Docs: learn.microsoft.com/dotnet/aspire GitHub: github.com/dotnet/aspire Stars: ~4k ⭐ | License: MIT (Open-Source, Microsoft-backed) Zielgruppe: Distributed Apps, Microservices, Cloud-Native-Projekte

Was ist .NET Aspire?

.NET Aspire ist keine Plattform für Business-Logic, sondern eine Orchestrierungs-Plattform für verteilte Anwendungen.

Die Vision: "Lokale Entwicklung mit 10+ Services soll so einfach sein wie dotnet run."

Was ist das Problem, das Aspire löst?

Szenario: E-Commerce mit Microservices

Sie haben:

  • Frontend (Blazor/React)
  • API-Gateway
  • Product-Service (ASP.NET Core)
  • Order-Service (ASP.NET Core)
  • Notification-Service (Worker-Service)
  • PostgreSQL (Datenbank)
  • Redis (Cache)
  • RabbitMQ (Message-Queue)

Ohne Aspire:

  1. Terminal 1: docker-compose up (PostgreSQL, Redis, RabbitMQ)
  2. Terminal 2: dotnet run --project Product.Service
  3. Terminal 3: dotnet run --project Order.Service
  4. Terminal 4: dotnet run --project Notification.Service
  5. Terminal 5: dotnet run --project API.Gateway
  6. Terminal 6: npm start (Frontend)

Probleme:

  • 6 Terminals offen
  • Manuelles Connection-String-Management
  • Keine zentrale Logs/Metrics
  • Service-Discovery manuell (Port-Konfiguration)

Mit Aspire:

dotnet run --project AppHost

Fertig. Alle Services starten automatisch.

Wie funktioniert .NET Aspire?

1. AppHost: Ihre Orchestrierungs-Definition

// AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

// Infrastructure
var postgres = builder.AddPostgres("postgres")
    .WithPgAdmin();  // PgAdmin UI automatisch verfügbar

var redis = builder.AddRedis("redis");
var messaging = builder.AddRabbitMQ("messaging");

// Services
var productService = builder.AddProject<Projects.ProductService>("product-service")
    .WithReference(postgres)
    .WithReference(redis);

var orderService = builder.AddProject<Projects.OrderService>("order-service")
    .WithReference(postgres)
    .WithReference(messaging)
    .WithReference(productService);  // Service-Discovery!

var notificationService = builder.AddProject<Projects.NotificationService>("notification-service")
    .WithReference(messaging);

var apiGateway = builder.AddProject<Projects.ApiGateway>("api-gateway")
    .WithReference(productService)
    .WithReference(orderService);

var frontend = builder.AddNpmApp("frontend", "../Frontend")
    .WithReference(apiGateway);

builder.Build().Run();

Was passiert beim Start:

  • PostgreSQL startet in Docker
  • Redis startet in Docker
  • RabbitMQ startet in Docker
  • Alle .NET-Projekte starten
  • Frontend (npm) startet
  • Developer-Dashboard öffnet sich automatisch

2. Service-Discovery: Automatisch

Services müssen nicht mehr wissen, wo andere Services laufen:

// Order-Service: Wie rufe ich Product-Service?
// OHNE Aspire:
var productServiceUrl = configuration["ProductService:Url"]; // Manuell konfigurieren
var httpClient = new HttpClient { BaseAddress = new Uri(productServiceUrl) };

// MIT Aspire:
builder.Services.AddHttpClient<IProductClient, ProductClient>(client =>
{
    client.BaseAddress = new Uri("http://product-service"); // Aspire resolved!
});

Aspire injiziert automatisch die korrekte URL (localhost:5001, kubernetes-service, etc.).

3. Developer-Dashboard: Alles an einem Ort

Das Dashboard zeigt in Echtzeit:

  • Resources: Welche Services/Datenbanken laufen?
  • Console-Logs: Alle Services in einer Ansicht
  • Structured-Logs: Filterable, durchsuchbar
  • Traces: Distributed-Tracing (Request durch mehrere Services)
  • Metrics: CPU, Memory, Request-Rate pro Service

Beispiel-Trace:

[12:34:56] API-Gateway: GET /api/orders/123
  └─ [12:34:56.100] Order-Service: GetOrderById(123)
      └─ [12:34:56.150] Product-Service: GetProductDetails(456)
          └─ [12:34:56.180] PostgreSQL: SELECT * FROM Products WHERE Id=456

Sie sehen den kompletten Request-Flow - über alle Services hinweg.

4. Integrations: Vorgefertigte Pakete

Aspire hat NuGet-Pakete für alle gängigen Services:

# PostgreSQL
dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL

# Redis
dotnet add package Aspire.StackExchange.Redis

# RabbitMQ
dotnet add package Aspire.RabbitMQ.Client

# OpenAI
dotnet add package Aspire.Azure.AI.OpenAI

# MongoDB, CosmosDB, Azure Service Bus, etc.

Usage:

// Product-Service
builder.AddNpgsqlDbContext<ProductDbContext>("postgres");

// Order-Service
builder.AddRedis("redis");

// Notification-Service
builder.AddRabbitMQClient("messaging");

Aspire injiziert automatisch:

  • Connection-Strings (aus AppHost)
  • Health-Checks
  • Telemetry (Logs, Traces, Metrics)

5. Deployment: Von lokal zu Kubernetes

Das Geniale: Dieselbe AppHost-Definition funktioniert überall:

# Lokal (Docker)
dotnet run --project AppHost

# Kubernetes (via Aspirate-Tool)
aspirate generate
kubectl apply -f aspire-manifest.yaml

# Azure Container Apps (via Azure-CLI)
azd init
azd up

Aspire generiert:

  • Docker-Compose-Files (für lokale Entwicklung)
  • Kubernetes-Manifests (für K8s-Deployment)
  • Bicep/Terraform (für Azure/AWS)

Wann sollten Sie .NET Aspire nutzen?

✅ Perfekt für:

  • Microservices-Architekturen (> 3 Services)
  • Cloud-Native-Projekte (Kubernetes, Container-Apps)
  • Teams mit verteilten Systemen (bessere Developer-Experience)
  • Projekte mit vielen Integrationen (DBs, Caches, Queues, AI-Services)
  • Observability-Requirements (Tracing, Metrics wichtig)

❌ Weniger geeignet für:

  • Monolithen (Overhead ohne Nutzen)
  • Einfache Web-Apps (1 API + 1 DB → zu viel Tooling)
  • Legacy-Projekte (Aspire braucht .NET 8+)

Der Trade-off: Komfort vs. Komplexität

Vorteile:

  • Enorme Developer-Experience: 10+ Services mit einem Befehl starten
  • Service-Discovery: Keine manuellen URLs mehr
  • Observability: Tracing, Logs, Metrics out-of-the-box
  • Deployment-Flexibilität: Lokal, Docker, Kubernetes, Cloud
  • Microsoft-backed: Langfristige Unterstützung garantiert

Nachteile:

  • ⚠️ Overhead bei kleinen Projekten: Für Monolithen zu viel Tooling
  • ⚠️ Noch jung: .NET 8+ erforderlich, Ecosystem wächst noch
  • ⚠️ Abstraktion: Versteckt Komplexität - schwieriger zu debuggen wenn etwas schief geht
  • ⚠️ Kein Framework: Aspire löst NICHT Architektur-Fragen (DDD, CQRS, etc.)

Vergleich: Wann welche Plattform?

Kriterium ASP.NET Core ABP Framework PlatformPlatform .NET Aspire
Projekt-Typ Alle Enterprise, SaaS SaaS-Startups Microservices
Team-Größe 1-50+ 5-100+ 2-20 3-50+
Learning-Curve ⭐⭐ Niedrig ⭐⭐⭐⭐ Hoch ⭐⭐⭐⭐ Hoch ⭐⭐⭐ Mittel
Produktivität (CRUD) ⭐⭐ Mittel ⭐⭐⭐⭐⭐ Sehr hoch ⭐⭐⭐ Hoch ⭐⭐ Mittel
Architektur-Vorgabe ❌ Keine ✅ DDD, Layers ✅ Vertical Slice, CQRS ❌ Keine
Multi-Tenancy ❌ Manuell ✅ Out-of-the-box ✅ Out-of-the-box ❌ Nicht relevant
Microservices-Support ⭐⭐⭐ Gut ⭐⭐ Mittel ⭐⭐⭐ Gut ⭐⭐⭐⭐⭐ Exzellent
DevOps-Tooling ⭐⭐ Basic ⭐⭐⭐ Gut ⭐⭐⭐⭐⭐ Exzellent ⭐⭐⭐⭐⭐ Exzellent
Observability ⭐⭐ Basic ⭐⭐⭐ Gut ⭐⭐⭐⭐ Sehr gut ⭐⭐⭐⭐⭐ Exzellent
Community ⭐⭐⭐⭐⭐ Riesig ⭐⭐⭐⭐ Groß ⭐⭐ Klein ⭐⭐⭐⭐ Wachsend
Lock-in-Risiko ✅ Kein ⚠️ Hoch ⚠️ Mittel (Fork) ⚠️ Mittel
Performance-Overhead ✅ Keiner ⚠️ Mittel ⚠️ Niedrig ⚠️ Niedrig
Lizenz-Kosten ✅ Kostenlos ⚠️ Open-Source + Commercial ✅ MIT (Kostenlos) ✅ MIT (Kostenlos)

Entscheidungs-Matrix

Ihr Projekt ist...

...ein einfaches Web-API (CRUD, < 10 Endpoints):ASP.NET Core (kein Framework nötig)

...eine Enterprise-Anwendung mit komplexer Business-Logic:ABP Framework (DDD, Multi-Tenancy, vorgefertigte Module)

...ein SaaS-Startup (B2B/B2C, Cloud-Native):PlatformPlatform (Modern, Security-First, DevOps-Automation)

...eine Microservices-Architektur (> 5 Services):.NET Aspire (Orchestrierung, Service-Discovery, Observability)

Kombination möglich?

  • ABP + Aspire: ABP für Business-Logic, Aspire für Microservices-Orchestrierung
  • PlatformPlatform + Aspire: PlatformPlatform als Monolith, später Aspire für Microservices
  • ABP + PlatformPlatform: Zu unterschiedliche Architektur-Ansätze

Das Fazit: Produktivität vs. Lock-in

Die Wahrheit über Developer-Plattformen

Alle drei Plattformen lösen ein echtes Problem:

  • ABP Framework: Reduziert repetitive CRUD-Code um 70-80%
  • PlatformPlatform: Gibt Ihnen einen Production-Ready-SaaS-Blueprint
  • .NET Aspire: Macht lokale Entwicklung mit Microservices praktikabel

Aber: Sie zahlen einen Preis.

Der Lock-in-Effekt

ABP Framework:

// Ihr Code ist voll von ABP-Abstraktionen
public class ProductAppService : ApplicationService, IProductAppService
{
    private readonly IRepository<Product> _repository;  // ABP-Abstraction

    [Authorize(MyPermissions.Products.Create)]  // ABP-Permission
    [UnitOfWork]  // ABP-UnitOfWork
    public async Task<ProductDto> CreateAsync(CreateProductDto input)
    {
        var product = ObjectMapper.Map<CreateProductDto, Product>(input);  // ABP-AutoMapper
        await _repository.InsertAsync(product);  // ABP-Repository
        return ObjectMapper.Map<Product, ProductDto>(product);
    }
}

Wollen Sie aus ABP raus? Sie müssen:

  • Alle IRepository<T> durch EF-Core-DbContext ersetzen
  • Permission-System neu implementieren
  • AutoMapper manuell konfigurieren
  • UnitOfWork-Pattern selbst implementieren

Aufwand: 3-6 Monate für mittelgroßes Projekt.

PlatformPlatform:

// Ihr Code folgt PlatformPlatform-Patterns
public record CreateProductCommand(string Name, decimal Price) : ICommand;

public class CreateProductHandler : ICommandHandler<CreateProductCommand>
{
    public async Task Handle(CreateProductCommand command, CancellationToken ct)
    {
        // Vertical-Slice-spezifischer Code
    }
}

Wollen Sie aus PlatformPlatform raus? Sie müssen:

  • Gesamte Architektur umbauen (Vertical Slice → Ihre Architektur)
  • CQRS-Abstraktionen entfernen
  • Domain-Events neu implementieren

Aufwand: 2-4 Monate (weniger als ABP, da Fork statt Framework).

.NET Aspire:

// Aspire-Code ist relativ entkoppelt
builder.AddNpgsqlDbContext<ProductDbContext>("postgres");

Wollen Sie aus Aspire raus? Sie müssen:

  • AppHost löschen (Services laufen weiterhin standalone)
  • Connection-Strings manuell konfigurieren
  • Service-Discovery selbst implementieren (oder Service-Mesh nutzen)

Aufwand: 1-2 Wochen (geringster Lock-in der drei Plattformen).

Die Opinionated-Nature

Alle drei Plattformen sind opinionated:

ABP sagt: "Du machst DDD, Layered-Architecture, und Multi-Tenancy so wie wir." PlatformPlatform sagt: "Du machst Vertical Slice, CQRS, und deployest zu Azure." .NET Aspire sagt: "Du machst Microservices mit OpenTelemetry und Service-Discovery."

Wenn Sie damit einverstanden sind: Enorme Produktivität. Wenn nicht: Frustrierender Kampf gegen das Framework.

Wann lohnt sich der Trade-off?

✅ Plattform lohnt sich, wenn:

  • Projekt ist langfristig (> 2 Jahre) - Lock-in ist OK
  • Team ist neu in .NET - Plattform gibt Struktur vor
  • Sie bauen typische Enterprise/SaaS-Features - Plattform hat das bereits
  • Time-to-Market ist wichtiger als volle Kontrolle

❌ Plattform lohnt sich NICHT, wenn:

  • Projekt ist kurz (< 6 Monate) - Learning-Curve überwiegt Nutzen
  • Sie haben spezifische Anforderungen, die nicht ins Plattform-Modell passen
  • Performance ist kritisch - Abstraktions-Layer kosten Performance
  • Team bevorzugt eigene Architektur - Kampf gegen Framework

Meine persönliche Empfehlung

Als CTO, der beides gesehen hat (mit und ohne Plattform):

1. Starten Sie mit ASP.NET Core + wenigen NuGet-Paketen

  • Lernen Sie, was ASP.NET Core kann
  • Implementieren Sie erste Features ohne Framework
  • Verstehen Sie, wo Sie repetitiven Code schreiben

2. Wenn repetitiver Code zu viel wird:

  • Enterprise/SaaS mit viel CRUD? → ABP Framework
  • Cloud-Native-SaaS-Startup? → PlatformPlatform (forken)
  • Microservices? → .NET Aspire

3. Evaluieren Sie nach 3-6 Monaten:

  • Ist die Plattform ein Produktivitäts-Boost oder eine Belastung?
  • Sind die Abstraktionen hilfreich oder limitierend?
  • Würden Sie die Plattform wieder wählen?

Die beste Architektur ist die, die Ihr Team versteht und produktiv nutzt - egal ob Framework oder Custom.


Weitere Ressourcen

.NET Architecture & Best-Practices:

Brauchen Sie Hilfe bei der Architektur-Entscheidung? Ich habe über 8 Jahre als .NET-CTO gearbeitet und Teams bei Framework-Evaluationen begleitet. Lassen Sie uns sprechen.

← Zurück zu allen Publikationen