Work in Progress
Diese Seite ist aktuell im Review! Die Seite wurde noch nicht qualitätsgesichert und kann Fehler enthalten.
Die verlinkten Seiten sind ggf. nur für Schleupen-Mitarbeiter sichtbar.

Domain Events

Zu verbesserten Strukturierung des Codes (z.B. von Usecase Controller-Logik) kann das Aggregat-Konzept konsequent weiter aufgebrochen werden, in dem zum Beispiel der Code bzgl. der Persistierung von Änderungen unterschiedlicher Aggregate entkoppelt wird. Insbesondere können Seiteneffekte von Änderungen über mehrere Aggregate mithilfe dieses Musters abgebildet werden - aber auch das Auslösen von Business Events. Die Entkopplung kann i.A. auch zeitlich erfolgen, was initial hier nicht abgebildet wird. Details zu Domain Events: Siehe https://docs.microsoft.com/de-de/dotnet/standard/microservices-architecture/microservice-ddd-cqrs-patterns/domain-events-design-implementation.

Hierdurch kann der Code der in Usecase Controllern erstellt wird, deutlich schlanker werden, sodass auch Wiederverwendung einfacher wird. Somit entfällt das Problem, Usecase Controller wiederverwenden zu wollen.

Vaughn Vernon gibt in seinem Buch "Implementing Domain Design" (Seite 360) den folgenden Ratschlag:

Both the referencing aggregate and the referenced aggregate must not be modified in the same transaction. Only one or the other may be modified in a single transaction.

Diese extreme Form nutzen wir bei Domain Events so nicht, sondern verwenden eine einfachere Form wie in https://learn.microsoft.com/de-de/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation beschrieben, bei der mehrere Events über MediatR innerhalb einer Transaktion gefahren werden.

Im Code startet die Kette bei uns im Usecase Controller, wobei die nachfolgenden Domain Events dann beim Flush des Repositories ausgelöst werden. Bei uns wird dann im Usecase Controller und in den nachfolgenden Events jeweils ein Aggregat editiert.

Design

Zunächst muss die Domäne dahingehend vorbereitet werden, dass Domain Events gesammelt werden. Das Sammeln erfolgt in der Domäne unter Zuhilfenahme des sogenannten DomainEventContainers. An geeigneter Stelle wird in der Domäne diesem das später auszulösende Event hinterlegt. Dieses wird durch Ableitung von INotification implementiert (Marker-Interface).

Domain Events werden im Unternamensraum DomainEvents unterhalb des Namensraums für das Aggregat im Domain-Projekt definiert:

Die Events selber werden letztendlich im Standard durch Flush() im Repository ausgelöst (Anschluss, siehe unten). Dies kann prinzipiell auch manuell an jeder anderen Stelle durch Injiziierung von IDomainEventPublisher erfolgen (siehe Auslösen von Events an beliebiger Codestelle).

Zur Behandlung von Events muss ein Event Handler durch Ableitung von INotificationHandler<TDomainEvent> implementiert werden. Die Handler werden im BusinessCases-Projekt, im Unternamensraum DomainEventHandler, abgelegt:

Folgende Nuget-Pakete müssen wie folgt angebunden werden:

  • das Domain-Projekt (sowie alle anhängigen Projekte) muss per paket.dependencies die Pakete Schleupen.CS.PI.Framework.Entities und Schleupen.CS.PI.Framework.Entities.DomainEvents referenzieren
  • das BusinessCases-Projekt muss das Paket Schleupen.CS.PI.Framework.Entities.DomainEvents referenzieren
  • Castle/NHibhernate-Anbindung
    • 1st-Edition
      • das Services-Projekt muss das Paket Schleupen.CS.PI.Framework.Entities.DomainEvents.Castle3.Wcf referenzieren (-> DomainEventsInstallerWcf)
      • das Repository-Projekt muss das Paket Schleupen.CS.PI.Framework.Entities.DomainEvents.NHibernate51 (und damit implizit Schleupen.CS.PI.Framework.Entities.DomainEvents) referenzieren
    • 2nd-Edition
      • das Services-Projekt muss das Paket Schleupen.CS.PI.Framework.Entities.DomainEvents.NHibernate51.2ndEdition.Castle3 referenzieren (-> DomainEventsInstallerWcf)
      • die Repository-Projekt muss das Paket Schleupen.CS.PI.Framework.Entities.DomainEvents.NHibernate51.2ndEdition (und damit implizit Schleupen.CS.PI.Framework.Entities.DomainEvents) referenzieren

Wenn die Domain Events wie hier im Standardverhalten beschrieben genutzt werden befindet sich der Code noch innerhalb der Transaktion. Hier also keine weitere Transaktion öffnen!

Ein Domain Event wird mit dem Postfix DomainEvent versehen:

<Fachliches Domänenereignis>DomainEvent

Beispiel: BuecherAusgeliehenDomainEvent

Die Bezeichnungskonvention der DomainEventHandler ist indes etwas komplizierter, da zum einen beschrieben wird, was zu tun ist und zum anderen am Ziel-Aggregat (fast) dasselbe getan werden, wenn unterschiedliche Events auftreten. Dieser Fall ist vermutlich selten, kann aber zu Namenskollisionen führen. Daher müssen beide Bestandteile in dem Namen des Handlers einfließen:

<Was fachlich zu tun ist>When<Fachliches Domänenereignis>DomainEventHandler

Beispiel: MarkiereBuecherWhenBuecherAusgeliehenDomainEventHandler

Abgrenzung

Domänenereignisse lösen keine Performance-Probleme oder ähnliches.

Stärken und Schwächen

Stärken
  • Loose Kopplung im Code
  • Isoliertere Testbarkeit ist möglich
Schwächen
  • Komplexität durch loose Kopplung
  • Mehr Aufwand bei integrativeren Tests

Benutzte Muster

Alternative Muster

Cookie Consent mit Real Cookie Banner