photo by :Felix Mittermeier

Doomain — C# Model synchronization

TodlyCodly
4 min readNov 25, 2021

There is good amount of information on Internet how to do Event Sourcing in proper way. I don’t want to go back to rules and how to do it. Good starting point to understand why Event Sourcing matter is:

Event Sourcing (martinfowler.com)

What I was always struggling to understand why Event Sourcing is alawys custom made. Maybe there is some way to attach this great technique to any model in any application.

This article is based on my repository which contains simple library and example mes1234/DomainPlayground (github.com)

Idea

Event Sourcing is based on idea of Log Of Events which is append only list, so one can alway revert state of on object to previous version. To make some generic library, set of Events needs to be predefined. Implementation of saving any arbitrary Event is simple, while replay logic might be more complicated, it would require a lot of reflection based code, which is always tricky.

For simplicity I used Repository Pattern (Designing the infrastructure persistence layer | Microsoft Docs ) so Events represents Repository operations:

  • Add or Update
  • Remove

Get is read only so it is not changing state of any object.

There are four major terms in library:

Entity — Any class which implements certain Interface — discussed later

Repository — plain old repository as milions out there in code

Event DispatcherMediatR based (jbogard/MediatR: Simple, unambitious mediator implementation in .NET (github.com)) dispatcher which routes notifications aka events.

Streaming — background service which publish and subscribes for events. I’ve added two implementations:

  • File based
  • Redis streaming based

Entity

Entity is any class which

  • can pack itself into binary
  • recreate itself from binary
  • has Id

I’ve added ICoder interface which helps Entity to encode/decode itself into binary format but it can also by

  • protobuf
  • json

Only expected behaviour for Entity is that it can serialze itself and deserialize.

This requires that any Event will contain serilized version of Entity and its Type so it can be recreated later on.

Usually when binary serialization takes place it needs to be devided into to parts:

  • Header, so reciving party can read metadata about content
  • Content

Repository

Biggest derail from real Event Sourcing approach is that actually only Repository is subject of Event Sourcing. As mentioned earlier notifications/events are :

  • Add or Update
  • Remove

what basiacally describes all interesting behaviour of Repository. Model/Entity can make a lot of thing between Add and Update operation which might be lost so its state and representation is only preserved when one want to put it to Repository.

In fully custom tailored Event Sourcing you can watch a movie about your model, every action is captured. Mine simple approach is more of set of photos.

Event Dispatcher

Event dispatcher might be complicated set of rules and routes how to handle Events traffic but when you use MediatR it becomes much more declarative:

Eg. both Event Dispatcher and Repository reacts to AddOrUpdateNotification to make it work all is needed

public class AddOrUpdateItemNotificationHandler : INotificationHandler<AddOrUpdateNotification>

and

public partial class Repository<T> : INotificationHandler<AddOrUpdateNotification>,

MediatR will take care of supplying any AddOrUpdateNotification to both.

Streaming

Streaming is an Background Service (Create a Windows Service using BackgroundService | Microsoft Docs)

To implement any Streaming medium:

All you need to do is implement some interfaces/methods :

public class RedisStreaming : BackgroundService, IStreaming
  • IStreaming is responsible for getting Outbound messages
public async Task Publish(Topic topic, byte[] msg)

BackgroundService main method constantly reacts to new messages in stream

protected override async Task ExecuteAsync(CancellationToken stoppingToken)

Summary

Can generic Event Sourcing lib be made.

Of course yes, but …

Events are foundation of any Event Sourcing it has quite complicated liftime:

  • emitted
  • preserved in stream
  • replayed

First and second can be automated but third phase is specific to any model and it is hard to prepare library which can handle it well.

Retrospective

What I like in every completed project is to understand what went wrong/good:

Good :

  • Selected architecture is quite easy to maintain. Switching between streaming solutions (Redis vs Files) did not require any changes in other parts of system.
  • Requirements what model needs to implement is lighweight. IEvent & IEntity interfaces are simple, and don’t limit model.

Bad:

  • It is not Event Sourcing, it is Repository with Snapshoting capability.
  • Every time Model is saved it is fully serialized, this should be using some kind of verification what changed and only saves difference ( like Git)

--

--

TodlyCodly
TodlyCodly

Written by TodlyCodly

C# developer, who once was Pythonista and dreams of being Golang guy.

No responses yet