LeVent is a simple .NET library designed to provide a local event subscribing/publishing capabilities to .NET developers.
Understanding the ideas around the Cul-De-Sac pattern is essential for taking advantage of LeVent.
Assume that you have multiple Foundation Services that want to be notified when an event occurs. You can create a simple EventBroker
that leverages LeVent to offer the registration and publishing capabilities as follows:
In the figure above, the EventBroker
leverages LeVent to offer subscribing and publishing capabilities as follows:
public ILeVentClient<Student> StudentEventClient { get; set; }
public async ValueTask PublishStudentEventAsync(Student student) =>
await this.StudentEventClient.PublishEventAsync(student);
public void RegisterStudentHandler(Func<Student, ValueTask> studentHandler) =>
this.StudentEventClient.RegisterEventHandler(studentHandler);
Then, a StudentEventService
will leverage the EventBroker
to allow higher-order services to register/listen or publish through that eventing mechanism as follows:
public class StudentEventService : IStudentEventService
{
private readonly IEventBroker eventBroker;
public StudentEventService(IEventBroker eventBroker) =>
this.eventBroker = eventBroker;
public async ValueTask PublishStudentEventAsync(Student student) =>
await this.eventBroker.PublishStudentEventAsync(student);
public void RegisterStudentEventHandler(Func<Student, ValueTask> studentEventHandler) =>
this.eventBroker.RegisterStudentHandler(studentEventHandler);
}
The next step is for Orchestration services to publish or listen to the event and call its dependencies.
In the case of a publisher - a StudentOrchestrationService
would be as follows:
public class StudentOrchestrationService : IStudentOrchestrationService
{
private readonly IStudentEventService studentEventService;
private readonly IStudentService studentService;
public StudentOrchestrationService(
IStudentEventService studentEventService,
IStudentService studentService)
{
this.studentEventService = studentEventService;
this.studentService = studentService;
}
public async ValueTask AddStudentAsync(Student student)
{
this.studentService.AddStudent(student);
await this.studentEventService.PublishStudentEventAsync(student);
}
}
The Orchestration service above will first add a Student
and then publish an event about that student for all listeners.
Let's check out what a listener would look like:
public class StudentLibraryOrchestrationService : IStudentLibraryOrchestrationService
{
private readonly IStudentEventService studentEventService;
private readonly IStudentLibraryService studentLibraryService;
public StudentLibraryOrchestrationService(
IStudentEventService studentEventService,
IStudentLibraryService studentLibraryService)
{
this.studentEventService = studentEventService;
this.studentLibraryService = studentLibraryService;
}
public void ListenToStudentEvents()
{
this.studentEventService.RegisterStudentEventHandler((student) =>
{
this.studentLibraryService.RegisterStudentLibaryCard(student);
return ValueTask.CompletedTask;
});
}
The StudentLibraryOrchestrationService
will receive a Student
event from whoever is publishing these events without coupling and act upon that very same event by creating a LibraryCard
.
This pattern is called Cul-De-Sac. It's an advanced low-level architecture technique to allow scaling and chaining to infinite number of events with no coupling whatsoever - here's how it looks in the 3D space:
The figure above assumes no dependence between one listener and the other. You can also leverage LeVent to allow the chaining of listeners as follows:
These patterns allow for more maintainable standardized systems wholly decoupled from their event source and capable of passing forward an event as an interceptor or completing a task and forwarding.
Here's the Low-Level Architecture of this library