Wie man nicht im Spaghetti-Code versinkt: Hexagonale Architektur in C#

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Wenn das Projekt zu einem Chaos wird

Haben Sie jemals ein C#-Projekt geöffnet, das vor einem Jahr geschrieben wurde, und mit Schrecken festgestellt, dass nichts geändert werden kann, ohne alles zu riskieren? Die Geschäftslogik ist eng mit Entity Framework verwoben, ASP.NET-Controller speichern Datenbankgeheimnisse, und Unit-Tests verwandeln sich in eine höllische Integration mit einer echten Datenbank. Kommt Ihnen das bekannt vor?

Dies ist ein klassisches Symptom fehlender Architektur. Die gute Nachricht: Es gibt ein bewährtes Rezept – die Hexagonale Architektur (auch bekannt als Ports & Adapters). Dieses von Alistair Cockburn entwickelte Muster ist nicht nur ein modischer Begriff. Es ist eine Rettung für mittlere und große Projekte in C#. Lassen Sie uns verstehen, wie es funktioniert, und gleich Code schreiben.



Das Wesen der Hexagonalen Architektur: Kern und Peripherie

Stellen Sie sich ein Sechseck (Hexagon) vor. Im Zentrum befindet sich Ihre Anwendung mit reiner Geschäftslogik, geschrieben in reinem C# ohne externe Abhängigkeiten. An den Rändern befinden sich Ports (Schnittstellen), über die der Kern mit der Außenwelt kommuniziert. Adapter sind die konkreten Implementierungen: ASP.NET-Controller, EF Core-Repositories, RabbitMQ-Clients.

Die Hauptregel: Der Kern weiß nichts über die Außenwelt. Er kennt nur seine Ports. Dies ermöglicht es, die Datenbank, die Benutzeroberfläche oder die Nachrichtenwarteschlangen zu ändern, ohne die Geschäftslogik zu verändern.



Warum ist das für C#-Entwickler wichtig?

  • Testbarkeit: Die Geschäftslogik kann ohne Datenbank, HTTP und Dateisystem getestet werden.
  • Flexibilität: Möchten Sie PostgreSQL durch MongoDB ersetzen? Sie ändern nur den Adapter.
  • Lesbarkeit: Der Code ähnelt eher einer Anforderungsspezifikation als einem Abhängigkeitsknäuel.
  • Einhaltung von SOLID: Insbesondere das Prinzip der Abhängigkeitsinversion (Dependency Inversion).


Projektstruktur in C#

In der Hexagonalen Architektur werden in der Regel drei Hauptschichten unterschieden. Für C# ist es praktisch, diese als separate Projekte in einer Lösung zu organisieren:



MyApp.sln├── MyApp.Domain          // Kern: Entitäten, Value Objects, Ports (Schnittstellen)├── MyApp.Application     // Use Cases (Anwendungsdienste)├── MyApp.Infrastructure  // Adapter: EF Core, externe APIs, Logging└── MyApp.Api             // Eingangsadapter: ASP.NET Controller / Minimal API


Beachten Sie: Domain und Application sind reine Klassenbibliotheken ohne Verweise auf Microsoft.AspNetCore oder EntityFramework. Nur System und System.Threading.Tasks.



Code schreiben: Ein Praxisbeispiel

Angenommen, wir entwickeln ein Bestellsystem. Wir müssen eine Bestellung erstellen und speichern.



Schritt 1: Der Kern (Domain)

Hier befinden sich die Entitäten und Ports – Schnittstellen, die definieren, wie der Kern mit der Welt kommuniziert.



// MyApp.Domain/Entities/Order.cspublic class Order{    public Guid Id { get; private set; }    public string CustomerName { get; private set; }    public decimal TotalAmount { get; private set; }    public DateTime CreatedAt { get; private set; }

public Order(string customerName, decimal totalAmount) { Id = Guid.NewGuid(); CustomerName = customerName; TotalAmount = totalAmount; CreatedAt = DateTime.UtcNow; }}

// MyApp.Domain/Ports/IOrderRepository.cs (Ausgangs-Port)public interface IOrderRepository{ Task<Order> GetByIdAsync(Guid id); Task AddAsync(Order order);}

// MyApp.Domain/Ports/IOrderNotifier.cs (Ausgangs-Port – Benachrichtigungen)public interface IOrderNotifier{ Task NotifyOrderCreatedAsync(Order order);}


Beachten Sie: IOrderRepository und IOrderNotifier sind Ports. Der Kern definiert, was er möchte, aber nicht wie es implementiert wird.



Schritt 2: Anwendungsfälle

Blogs

Buchempfehlungen