Laden...

ASP.net MVC CQRS + eventsourcing

Erstellt von M@TUK vor 8 Jahren Letzter Beitrag vor 8 Jahren 1.038 Views
M
M@TUK Themenstarter:in
402 Beiträge seit 2005
vor 8 Jahren
ASP.net MVC CQRS + eventsourcing

Hi...

hat sich schon mal jemand eingehender mit CQRS und event sourcing bei asp.net mvc beschäftig?

Hab mir schon einiges an Posts und Videos dazu angesehen.

Ein paar Punkte sind mir aber noch unklar bzw. steig ich nicht dahinter wenn z.B. die "Kommunikation" über einen Service-Bus erfolgt.

  • Validierung im Client, im API-Controller, im Command/BL?
  • Wie kämen z.B. Validierungs oder BL-Exceptions zurück an den Client? Eine "Response" im herkömmlichen Sinn gibt's ja dann nicht mehr wenn das im Command/BL auftritt?
  • Selbes Response-Problem bei "Erfolg" wenn z.B. der Client bei Erfolg noch etwas tun soll (Grid reloaden, Info-Message "erfolgreich..." ausgeben...). Muss man hier auf Websockets zurückgreifen?

lg

16.807 Beiträge seit 2008
vor 8 Jahren

Unabhängig ob CQRS oder nicht sollte jede Schicht/Stack eine Validierung haben.
Man muss aber bei CQRS sehr viel in der API selbst machen, da zB nicht mit 200 als Statuscode geantwortet wird, sondern 202 (Accepted).

Wenn eine Validierung fehl schlägt wird mit 412 (Precondition Failed) geantwortet.

WebSockets brauchst Du keine. Wüsste aktuell nicht wo.

M
M@TUK Themenstarter:in
402 Beiträge seit 2005
vor 8 Jahren

Hi...

ich verstehe den Ablauf so (vielleicht ist da ja schon der Hund begraben).

Formular (Name, Strasse, Ort)
=> POST an APIController-Action
=> APIController-Action erstellt AddCommand und sendet ihn an CommandQueue
=> Service empfängt Message
=> Handler führt Command aus
=> Event wird an den EventQueue übergeben
=> usw... (event speichern, ReadModel aktualisieren, sagas....)

Validierung im Formular ist kein Problem, Validierung in der APIController-Action ist auch kein Problem, bei beiden kann ich ja sofort eine Response zurückliefern.

Wenn aber im Command die Validierung oder BL fehlschlägt, wie informiere ich dann den Client? Es gibt ja kein "return" bzw. keine direkte Verbindung zwischen Command und Client weil die Kommunikation über Messagebus läuft.

lg

742 Beiträge seit 2005
vor 8 Jahren

Bei CQRS wird oft alles in einen Topf geworfen, das ist aber nicht notwendig.

Erstmal geht es nur um die Trennung der Read und Write Seite. Das hat insbesondere den Vorteil, dass man beide Seiten getrennt optimieren kann. Zum Beispiel Normalisieren auf der Write Seite (=> Konstistenz) und Denormalisieren auf der Read Seite (=> Performance).

Dann kann man verschiedene Lösungen einsetzen um Komponenten weiter zu entkoppeln, beispielsweise Command Queues usw.

Ich setze CQRS in 2 Anwendungen ein, aber mit verschiedenem Stack / Ausprägungen. Das nur dazu.

Wenn eine Validierung im BL fehlschlägt brauchst du eien asynchrone Rückmeldung, z.B. per Mail:

"Deine Buchung konnte leider nicht durchgeführt werden, weil in der Zwischenzeit alle Plätze belegt wurden."

oder ein SignalR Popup usw.

Gleichzeitig kann es sein, dass du Änderungen durch Kompensation Events rückgängig machen musst.

M
M@TUK Themenstarter:in
402 Beiträge seit 2005
vor 8 Jahren

oder ein SignalR Popup usw.

genau das meinte ich mit WebSocket-Verbindung.

Danke für das Feedback.

lg

742 Beiträge seit 2005
vor 8 Jahren

Wir haben ein kleines Testprojekt entwickelt, um neue Konzepte zu probieren. Mit SignalR und GetEventStore.

Hierbei hängen wir uns einfach in den EventBus und geben alle Events an die Webseite raus. Das cool ist, man kann praktisch gemeinsam arbeiten, weil Änderungen von anderen Nutzern gleich mit gegeben werden.



public sealed class EventBroker : DisposableObject
    {
        private readonly Lazy<IHubContext> context = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<EventHub>());

        public EventBroker(IEventBus eventBus)
        {
            eventBus.SubscribeLive<TestGroupCreated>(async envelope =>
            {
                if (!IsDisposed)
                {
                    await context.Value.Clients.All.testGroupCreated(new TestGroupModel(envelope));
                }
            });
            ...
         }
    }