Mikroservices in C#: Architektur und Praxis auf fortgeschrittenem Niveau

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

Mikroservices in C#: Architektur und Praxis auf fortgeschrittenem Niveau



Der Übergang vom Monolithen zur Mikroservice-Architektur auf der .NET-Plattform ist nicht nur eine technische Entscheidung, sondern ein strategischer Schritt hin zu Skalierbarkeit und Ausfallsicherheit. Auf fortgeschrittenem Niveau stehen Entwickler jedoch vor nicht trivialen Herausforderungen: verteilte Transaktionen, Datenkonsistenz und komplexe Orchestrierung. In diesem Artikel analysieren wir die Architekturmuster, die helfen, ein zuverlässiges Mikroservice-Ökosystem in C# aufzubauen, und betrachten praktische Codebeispiele.



1. Saga-Pattern: Verwaltung verteilter Transaktionen



In Mikroservices sind herkömmliche ACID-Transaktionen nicht möglich. Das Saga-Pattern löst das Problem der Datenkonsistenz, indem es eine globale Operation in eine Abfolge lokaler Transaktionen mit kompensierenden Aktionen aufteilt.



Choreografie vs. Orchestrierung:

  • Choreografie – jeder Service veröffentlicht Ereignisse und reagiert darauf. Geeignet für einfache Szenarien.
  • Orchestrierung – ein zentraler Koordinator (Orchestrator) verwaltet die Schritte. Empfohlen für komplexe Geschäftsprozesse.


Beispiel einer Orchestrator-Implementierung in C# mit MassTransit:



public class OrderSaga : MassTransitStateMachine<OrderSagaState>{    public State Submitted { get; set; }    public State PaymentPending { get; set; }    public State Completed { get; set; }

public Event<OrderSubmitted> OrderSubmitted { get; set; } public Event<PaymentProcessed> PaymentProcessed { get; set; } public Event<PaymentFailed> PaymentFailed { get; set; }

public OrderSaga() { InstanceState(x => x.CurrentState);

Initially( When(OrderSubmitted) .Then(context => context.Saga.OrderId = context.Message.OrderId) .TransitionTo(Submitted) .Publish(context => new ProcessPayment { OrderId = context.Saga.OrderId, Amount = context.Message.Amount }) );

During(Submitted, When(PaymentProcessed) .TransitionTo(Completed) .Finalize(), When(PaymentFailed) .Then(context => Console.WriteLine("Kompensation: Stornierung der Bestellung")) .TransitionTo(Final) ); }}


Dieser Code zeigt, wie der Orchestrator den Lebenszyklus einer Bestellung verwaltet: Bei erfolgreicher Zahlung wird die Saga abgeschlossen, bei einem Fehler wird die Kompensation gestartet.



2. CQRS und Event Sourcing: Trennung der Verantwortlichkeiten



Das CQRS-Pattern (Command Query Responsibility Segregation) trennt Befehle (Schreiben) und Abfragen (Lesen) in verschiedene Modelle. In Kombination mit Event Sourcing (ES) bietet es vollständige Auditierbarkeit und Flexibilität.



CQRS+ES-Architektur:

  • Befehle – ändern den Zustand durch Ereignisse.
  • Ereignisse – werden im Event Store gespeichert (z. B. EventStoreDB).
  • Projektionen – erstellen Read-Modelle für schnelle Abfragen.


Beispiel eines Befehls und Handlers:



public class CreateOrderCommand : ICommand{    public Guid OrderId { get; set; }    public decimal Amount { get; set; }}

public class CreateOrderHandler : ICommandHandler<CreateOrderCommand>{ private readonly IEventStore _eventStore;

public async Task Handle(CreateOrderCommand command) { var orderCreated = new OrderCreatedEvent { OrderId = command.OrderId, Amount = command.Amount, Timestamp = DateTime.UtcNow };

await _eventStore.AppendEventAsync( $"order-{command.OrderId}", orderCreated ); }

Blogs

Buchempfehlungen