Skip to content

Commit c9b9413

Browse files
committed
version 3
1 parent d90f8fc commit c9b9413

File tree

9 files changed

+195
-160
lines changed

9 files changed

+195
-160
lines changed

README.md

+56-78
Original file line numberDiff line numberDiff line change
@@ -162,43 +162,48 @@ The library is built with DI as a first class concept. Wiring it up is easy. Thi
162162
public static ServiceProvider GetContainer() {
163163
var services = new ServiceCollection();
164164
165-
// Wiring up the event storage provider. "https://eventstore.com/" in this example
165+
// >> Step 1: Register the storage provider
166166
167-
// Event Store specific settings etc
168-
services.AddScoped<IEventStoreSettings, EventStoreSettings>(
169-
(sp) => new EventStoreSettings(SnapshotFrequency, PageSize));
170-
services.AddScoped<IEventStoreStorageConnectionProvider, EventStoreStorageConnectionProvider>();
171-
services.AddScoped<IEventStoreStorageCore, EventStoreStorageCore>();
167+
// Wiring up the event storage provider. "https://eventstore.com/" in this example
168+
// Event Store specific settings etc
169+
services.AddScoped<IEventStoreSettings, EventStoreSettings>(
170+
(sp) => new EventStoreSettings(SnapshotFrequency, PageSize));
171+
services.AddScoped<IEventStoreStorageConnectionProvider, EventStoreStorageConnectionProvider>();
172+
services.AddScoped<IEventStoreStorageCore, EventStoreStorageCore>();
172173
173-
// The storage provider implementations
174-
services.AddScoped<IEventStorageProvider<Guid>, EventStoreEventStorageProvider>();
175-
services.AddScoped<ISnapshotStorageProvider<Guid>, EventStoreSnapshotStorageProvider>();
174+
// The storage provider implementations
175+
services.AddScoped<IEventStorageProvider<Guid>, EventStoreEventStorageProvider>();
176+
services.AddScoped<ISnapshotStorageProvider<Guid>, EventStoreSnapshotStorageProvider>();
176177
177-
// Register the repository
178-
services.AddScoped<IRepository<Schedule, Guid, Guid>, Repository<Schedule, ScheduleSnapshot>>();
179-
// If you prefer to work without snapshots and use events only repository
180-
// services.AddScoped<IRepository<Schedule, Guid, Guid>, EventOnlyRepository<Schedule>>();
178+
// >> Step 2: Register the Repository and Session
181179
182-
// register the session implementation for the Aggregate
183-
services.AddScoped<ISession<Schedule>, Session<Schedule>>();
184-
// or if prefer to you use the more detailed interface
185-
// services.AddScoped<ISession<Schedule, Guid, Guid>, Session<Schedule>>();
180+
// Use the extension method "ScanAndRegisterAggregates()" in the
181+
// "NEventLite.Extensions.Microsoft.DependencyInjection" nuget library as shown below
186182
187-
// Or
188-
// Instead of specifying each Aggregate and Snapshot type you can use the convenience
189-
// extension method "ScanAndRegisterAggregates()" in the
190-
// "NEventLite.Extensions.Microsoft.DependencyInjection" nuget library as shown below
183+
services.ScanAndRegisterAggregates();
191184
192-
// services.ScanAndRegisterAggregates();
185+
// Or if you prefer to register the manually
193186
194-
// Use the defaults
195-
services.AddSingleton<IClock, DefaultSystemClock>();
196-
services.AddSingleton<IEventPublisher, DefaultNoOpEventPublisher>();
187+
// Register the repository
188+
services.AddScoped<IRepository<Schedule, Guid, Guid>, Repository<Schedule, ScheduleSnapshot, Guid, Guid, Guid>>();
189+
// If you prefer to work without snapshots and use events only repository
190+
// services.AddScoped<IRepository<Schedule, Guid, Guid>, EventOnlyRepository<Schedule>>();
197191
198-
// Or
199-
// use your own implementation
200-
// services.AddSingleton<IClock, MyClock>();
201-
// services.AddSingleton<IEventPublisher, MyEventPublisher>();
192+
// register the session implementation for the Aggregate
193+
services.AddScoped<ISession<Schedule>, Session<Schedule>>();
194+
// or if prefer to you use the more detailed interface
195+
// services.AddScoped<ISession<Schedule, Guid, Guid>, Session<Schedule>>();
196+
197+
// >> Step 3: Register the other required dependencies
198+
199+
// Use the defaults
200+
services.AddSingleton<IClock, DefaultSystemClock>();
201+
services.AddSingleton<IEventPublisher, DefaultNoOpEventPublisher>();
202+
203+
// Or
204+
// use your own implementation
205+
// services.AddSingleton<IClock, MyClock>();
206+
// services.AddSingleton<IEventPublisher, MyEventPublisher>();
202207
203208
var container = services.BuildServiceProvider();
204209
return container;
@@ -208,60 +213,33 @@ The library is built with DI as a first class concept. Wiring it up is easy. Thi
208213
If you want to use it with a different dependency injection framework, you can look at how the assembly scanning and registration is implemented for `Microsoft.Extensions.DependencyInjection` as an example and come up with your own implementation. The file is [located here](https://github.com/dasiths/NEventLite/blob/master/src/Extensions/NEventLite.Extensions.Microsoft.DependencyInjection/Extensions.cs).
209214

210215
```csharp
211-
public static void ScanAndRegisterAggregates<TAggregateKey, TEventKey>(this ServiceCollection services, IList<Assembly> assemblies)
216+
public static void ScanAndRegisterAggregates(this ServiceCollection services, IList<Assembly> assemblies)
217+
{
218+
foreach (var a in assemblies.GetAllAggregates()) // Use the built in GetAllAggregates() extensions method to find aggregate information
212219
{
213-
var allAggregates = assemblies
214-
.SelectMany(a =>
215-
a.GetTypes()
216-
.Where(t => t.IsClass && !t.IsAbstract & typeof(AggregateRoot<TAggregateKey, TEventKey>).IsAssignableFrom(t)))
217-
.ToList();
218-
219-
220-
foreach (var aggregateType in allAggregates)
221-
{
222-
services.RegisterAggregate<TAggregateKey, TEventKey>(aggregateType);
223-
}
220+
services.RegisterAggregate(a);
224221
}
222+
}
225223

226-
public static void RegisterAggregate<TAggregateKey, TEventKey>(this ServiceCollection services, Type aggregateType)
224+
public static void RegisterAggregate(this ServiceCollection services, AggregateInformation a)
225+
{
226+
// Register full generic types
227+
services.AddScoped(typeof(IRepository<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey),
228+
a.Snapshot != null
229+
? typeof(Repository<,,,,>).MakeGenericType(a.Aggregate, a.Snapshot, a.AggregateKey,
230+
a.EventKey, a.SnapshotKey)
231+
: typeof(EventOnlyRepository<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey));
232+
233+
services.AddScoped(typeof(ISession<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey),
234+
typeof(Session<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey));
235+
236+
// Register the convenience GUID scoped ISession interface as well
237+
if (a.AggregateKey == typeof(Guid) && a.EventKey == typeof(Guid))
227238
{
228-
var snapshottableSimple = aggregateType.GetInterfaces().FirstOrDefault(i =>
229-
i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(ISnapshottable<>)));
230-
231-
var snapshottableComplex = aggregateType.GetInterfaces().FirstOrDefault(i =>
232-
i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(ISnapshottable<,,>)));
233-
234-
Type snapshotType = null;
235-
Type snapshotKeyType = null;
236-
237-
if (snapshottableSimple != null)
238-
{
239-
snapshotType = snapshottableSimple.GetGenericArguments()[0];
240-
snapshotKeyType = typeof(Guid);
241-
}
242-
else if (snapshottableComplex != null)
243-
{
244-
snapshotType = snapshottableComplex.GetGenericArguments()[0];
245-
snapshotKeyType = snapshottableComplex.GetGenericArguments()[2];
246-
}
247-
248-
// Register full generic types
249-
services.AddScoped(typeof(IRepository<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)),
250-
snapshotType != null
251-
? typeof(Repository<,,,,>).MakeGenericType(aggregateType, snapshotType, typeof(TAggregateKey),
252-
typeof(TEventKey), snapshotKeyType)
253-
: typeof(EventOnlyRepository<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)));
254-
255-
services.AddScoped(typeof(ISession<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)),
256-
typeof(Session<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)));
257-
258-
// Register the convenience GUID scoped ISession interface as well
259-
if (typeof(TAggregateKey) == typeof(Guid) && typeof(TEventKey) == typeof(Guid))
260-
{
261-
services.AddScoped(typeof(ISession<>).MakeGenericType(aggregateType),
262-
typeof(Session<>).MakeGenericType(aggregateType));
263-
}
239+
services.AddScoped(typeof(ISession<>).MakeGenericType(a.Aggregate),
240+
typeof(Session<>).MakeGenericType(a.Aggregate));
264241
}
242+
}
265243
```
266244

267245
## :ledger: Storage providers

appveyor.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: 2.1.{build}
1+
version: 3.0.{build}
22
pull_requests:
33
do_not_increment_build_number: true
44
branches:

src/Extensions/NEventLite.Extensions.Microsoft.DependencyInjection/Extensions.cs

+16-51
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,44 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using System.Reflection;
54
using Microsoft.Extensions.DependencyInjection;
6-
using NEventLite.Core;
7-
using NEventLite.Core.Domain;
85
using NEventLite.Repository;
9-
using NEventLite.Storage;
6+
using NEventLite.Util;
107

118
namespace NEventLite.Extensions.Microsoft.DependencyInjection
129
{
1310
public static class Extensions
1411
{
1512
public static void ScanAndRegisterAggregates(this ServiceCollection services)
1613
{
17-
services.ScanAndRegisterAggregates<Guid, Guid>();
14+
services.ScanAndRegisterAggregates(AppDomain.CurrentDomain.GetAssemblies());
1815
}
1916

20-
public static void ScanAndRegisterAggregates<TAggregateKey, TEventKey>(this ServiceCollection services)
17+
public static void ScanAndRegisterAggregates(this ServiceCollection services, IList<Assembly> assemblies)
2118
{
22-
services.ScanAndRegisterAggregates<TAggregateKey, TEventKey>(AppDomain.CurrentDomain.GetAssemblies());
23-
}
24-
25-
public static void ScanAndRegisterAggregates<TAggregateKey, TEventKey>(this ServiceCollection services, IList<Assembly> assemblies)
26-
{
27-
var allAggregates = assemblies
28-
.SelectMany(a =>
29-
a.GetTypes()
30-
.Where(t => t.IsClass && !t.IsAbstract & typeof(AggregateRoot<TAggregateKey, TEventKey>).IsAssignableFrom(t)))
31-
.ToList();
32-
33-
34-
foreach (var aggregateType in allAggregates)
19+
foreach (var a in assemblies.GetAllAggregates())
3520
{
36-
services.RegisterAggregate<TAggregateKey, TEventKey>(aggregateType);
21+
services.RegisterAggregate(a);
3722
}
3823
}
3924

40-
public static void RegisterAggregate<TAggregateKey, TEventKey>(this ServiceCollection services, Type aggregateType)
25+
public static void RegisterAggregate(this ServiceCollection services, AggregateInformation a)
4126
{
42-
var snapshottableSimple = aggregateType.GetInterfaces().FirstOrDefault(i =>
43-
i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(ISnapshottable<>)));
44-
45-
var snapshottableComplex = aggregateType.GetInterfaces().FirstOrDefault(i =>
46-
i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(ISnapshottable<,,>)));
47-
48-
Type snapshotType = null;
49-
Type snapshotKeyType = null;
50-
51-
if (snapshottableSimple != null)
52-
{
53-
snapshotType = snapshottableSimple.GetGenericArguments()[0];
54-
snapshotKeyType = typeof(Guid);
55-
}
56-
else if (snapshottableComplex != null)
57-
{
58-
snapshotType = snapshottableComplex.GetGenericArguments()[0];
59-
snapshotKeyType = snapshottableComplex.GetGenericArguments()[2];
60-
}
61-
6227
// Register full generic types
63-
services.AddScoped(typeof(IRepository<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)),
64-
snapshotType != null
65-
? typeof(Repository<,,,,>).MakeGenericType(aggregateType, snapshotType, typeof(TAggregateKey),
66-
typeof(TEventKey), snapshotKeyType)
67-
: typeof(EventOnlyRepository<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)));
28+
services.AddScoped(typeof(IRepository<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey),
29+
a.Snapshot != null
30+
? typeof(Repository<,,,,>).MakeGenericType(a.Aggregate, a.Snapshot, a.AggregateKey,
31+
a.EventKey, a.SnapshotKey)
32+
: typeof(EventOnlyRepository<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey));
6833

69-
services.AddScoped(typeof(ISession<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)),
70-
typeof(Session<,,>).MakeGenericType(aggregateType, typeof(TAggregateKey), typeof(TEventKey)));
34+
services.AddScoped(typeof(ISession<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey),
35+
typeof(Session<,,>).MakeGenericType(a.Aggregate, a.AggregateKey, a.EventKey));
7136

7237
// Register the convenience GUID scoped ISession interface as well
73-
if (typeof(TAggregateKey) == typeof(Guid) && typeof(TEventKey) == typeof(Guid))
38+
if (a.AggregateKey == typeof(Guid) && a.EventKey == typeof(Guid))
7439
{
75-
services.AddScoped(typeof(ISession<>).MakeGenericType(aggregateType),
76-
typeof(Session<>).MakeGenericType(aggregateType));
40+
services.AddScoped(typeof(ISession<>).MakeGenericType(a.Aggregate),
41+
typeof(Session<>).MakeGenericType(a.Aggregate));
7742
}
7843
}
7944
}

src/NEventLite.Tests.Integration/EndToEndTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public EndToEndTests()
4444

4545
_clock = new MockClock();
4646
_eventPublisher = new MockEventPublisher();
47-
_repository = new Repository<Schedule, ScheduleSnapshot>(_clock, eventStorage, _eventPublisher, snapshotStorage);
48-
_eventOnlyRepository = new EventOnlyRepository<Schedule>(_clock, eventStorage, _eventPublisher);
47+
_repository = new Repository<Schedule, ScheduleSnapshot, Guid, Guid, Guid>(_clock, eventStorage, _eventPublisher, snapshotStorage);
48+
_eventOnlyRepository = new EventOnlyRepository<Schedule, Guid, Guid>(_clock, eventStorage, _eventPublisher);
4949
}
5050

5151
[Fact]

src/NEventLite/Repository/EventOnlyRepository.cs

-10
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@
66

77
namespace NEventLite.Repository
88
{
9-
public class EventOnlyRepository<TAggregate> :
10-
EventOnlyRepository<TAggregate, Guid, Guid>
11-
where TAggregate : AggregateRoot<Guid, Guid>, new()
12-
{
13-
public EventOnlyRepository(IClock clock, IEventStorageProvider<Guid> eventStorageProvider, IEventPublisher eventPublisher) :
14-
base(clock, eventStorageProvider, eventPublisher)
15-
{
16-
}
17-
}
18-
199
public class EventOnlyRepository<TAggregate, TAggregateKey, TEventKey> : Repository<TAggregate, IMockSnapShot<TAggregateKey>, TAggregateKey, TEventKey, IMockSnapshotKeyType>
2010
where TAggregate : AggregateRoot<TAggregateKey, TEventKey>, new()
2111
{

src/NEventLite/Repository/Repository.cs

-14
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,6 @@
1010

1111
namespace NEventLite.Repository
1212
{
13-
public class Repository<TAggregate, TSnapshot> :
14-
Repository<TAggregate, TSnapshot, Guid, Guid, Guid>
15-
where TAggregate : AggregateRoot<Guid, Guid>, new()
16-
where TSnapshot : ISnapshot<Guid, Guid>
17-
{
18-
public Repository(IClock clock,
19-
IEventStorageProvider<Guid> eventStorageProvider,
20-
IEventPublisher eventPublisher,
21-
ISnapshotStorageProvider<Guid> snapshotStorageProvider) :
22-
base(clock, eventStorageProvider, eventPublisher, snapshotStorageProvider)
23-
{
24-
}
25-
}
26-
2713
public class Repository<TAggregate, TSnapshot, TAggregateKey, TEventKey, TSnapshotKey> :
2814
IRepository<TAggregate, TAggregateKey, TEventKey>
2915
where TAggregate : AggregateRoot<TAggregateKey, TEventKey>, new()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
3+
namespace NEventLite.Util
4+
{
5+
public class AggregateInformation
6+
{
7+
public readonly bool IsValidResult;
8+
9+
public Type Aggregate { get; set; }
10+
public Type AggregateKey { get; set; }
11+
public Type EventKey { get; set; }
12+
public Type Snapshot { get; set; }
13+
public Type SnapshotKey { get; set; }
14+
15+
private AggregateInformation(Type aggregate, Type aggregateKey, Type eventKey, Type snapshot, Type snapshotKey)
16+
{
17+
IsValidResult = true;
18+
Aggregate = aggregate;
19+
AggregateKey = aggregateKey;
20+
EventKey = eventKey;
21+
Snapshot = snapshot;
22+
SnapshotKey = snapshotKey;
23+
}
24+
25+
private AggregateInformation()
26+
{
27+
IsValidResult = false;
28+
}
29+
30+
public static AggregateInformation ValidResult(Type aggregate, Type aggregateKey, Type eventKey, Type snapshot, Type snapshotKey)
31+
=> new AggregateInformation(aggregate, aggregateKey, eventKey, snapshot, snapshotKey);
32+
public static AggregateInformation InvalidResult => new AggregateInformation();
33+
}
34+
}

0 commit comments

Comments
 (0)