https://github.com/huysentruitw/projecto
Managed .NET (C#) library for handling CQRS/ES projections while maintaining the event sequence order
https://github.com/huysentruitw/projecto
Last synced: 4 months ago
JSON representation
Managed .NET (C#) library for handling CQRS/ES projections while maintaining the event sequence order
- Host: GitHub
- URL: https://github.com/huysentruitw/projecto
- Owner: huysentruitw
- License: apache-2.0
- Created: 2017-03-28T21:19:15.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2020-06-25T10:57:28.000Z (almost 5 years ago)
- Last Synced: 2024-05-01T14:50:19.790Z (12 months ago)
- Language: C#
- Size: 101 KB
- Stars: 2
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Projecto
[](https://ci.appveyor.com/project/huysentruitw/projecto/branch/master)
## Overview
Managed .NET 4.7.1 / .NET Core library for handling CQRS/ES projections while maintaining the event sequence order.
## Get it on [NuGet](https://www.nuget.org/packages/Projecto/)
PM> Install-Package Projecto
## Concepts / usage
### MessageEnvelope
A message envelope is a user-defined object (must derive from MessageEnvelope) that wraps a message before it is passed to `projector.Project()` which in turn passes the envelope to the `When<>()` handler inside the projection.
It's a convenient way to pass out-of-band data to the handler (f.e. the originating command id, or creation date of the event/message).
### Projection
Inherit from `Projection` to define a projection, where `string` is the type of the unique key for identifying projections, `TConnection` is the connection type used by the projection and `TMessageEnvelope` is the user-defined message envelope object (see previous topic).
```csharp
public class ExampleProjection : Projection
{
public ExampleProjection()
{
When(async (dataContext, envelope, @event) =>
{
dataContext.UserProfiles.Add(...);// Data can be saved directly or during collection disposal for batching queries (see `ProjectScope`)
await dataContext.SaveChangesAsync();
});
}
}
```### Projector
The projector reflects the sequence number of the most out-dated projection.
Use the projector to project one or more events/messages to all registered projections.
The projector ensures that it only handles events/messages in the correct order, starting with event/message with a sequence number equal to the number as returned from `GetNextSequenceNumber()`.
The number returned by the `GetNextSequenceNumber()` method of the projector can be used by the application to request a resend of missing events/messages during startup.
The `ProjectorBuilder` class is used to build a projector instance.
### ProjectorBuilder
```csharp
var disposalCallbacks = new ExampleCollectionDisposalCallbacks();var projector = new ProjectorBuilder()
.Register(new ExampleProjection())
.SetDependencyLifetimeScopeFactory(new ExampleDependencyLifetimeScopeFactory())
.Build();
```### DependencyLifetimeScope
A dependency lifetime scope is a scope that is created and disposed inside the call to `projector.Project`. The projector uses the `DependencyLifetimeScopeFactory` to create a disposable `DependencyLifetimeScope`. The dependency lifetime scope is responsible for resolving the NextSequenceNumberRepository as well as connections on request by one or more projections and has `ScopeEnded` and `DependencyResolved` events to have more control over the lifetime of the used dependencies.
```csharp
public class ExampleDependencyLifetimeScopeFactory : IDependencyLifetimeScopeFactory
{
public IDependencyLifetimeScope BeginLifetimeScope()
{
return new ExampleDependencyLifetimeScope();
}
}public class ExampleDependencyLifetimeScope : IDependencyLifetimeScope
{
public ExampleDependencyLifetimeScope()
{
}public void Dispose()
{
// Called when the project scope gets disposed
}public object Resolve(Type dependencyType)
{
if (dependencyType == typeof(ApplicationDbContext)) return new ApplicationDbContext();
if (dependencyType == typeof(MyNextSequenceNumberRepository)) return new MyNextSequenceNumberRepository();
throw new Exception($"Can't resolve unknown dependency type {dependencyType.Name}");
}
}
```### Autofac integration
An additional package exists for integration with Autofac. Get it on [NuGet](https://www.nuget.org/packages/Projecto.Autofac/):
PM> Install-Package Projecto.Autofac
Now the configuration of the projector can be simplified to this:```csharp
autofacContainer.RegisterType().SingleInstance();autofacContainer.Register(ctx => new ProjectorBuilder()
.RegisterProjectionsFromAutofac(ctx)
.UseAutofacDependencyLifetimeScopeFactory(ctx)
.Build()
).AsSelf().SingleInstance();
```