Skip to content

Commit e9d9d80

Browse files
committed
Merge branch 'develop'
2 parents cbb45fa + 887501f commit e9d9d80

18 files changed

Lines changed: 294 additions & 76 deletions

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,27 @@ share it by creating an issue with the link.
132132
- [The Unit of Work and Transactions In Domain Driven Design](http://blog.sapiensworks.com/post/2015/09/02/DDD-and-UoW/)
133133
by Mike Mogosanu
134134

135+
## How to contribute
136+
137+
EventFlow still needs a lot of love and if you want to help out there are
138+
several areas that you could help out with.
139+
140+
* **Features:** If you have a great idea for EventFlow, create a pull request.
141+
It might be a finished idea or just some basic concepts showing the feature
142+
outline
143+
* **Pull request feedback:** Typically there are several pull requests marked
144+
with the `in progress` and feedback is always welcome. Please note that the
145+
quality of the code here might not be "production ready", especially if
146+
the pull request is marked with the `prof of concept` label
147+
* **Documentation:** Good documentation is very important for any library and
148+
is also very hard to do properly, so if spot a spelling error, think up
149+
a good idea for a guide or just have some comments, then please create
150+
either a pull request or an issue
151+
* **Information sharing:** Working with CQRS+ES and DDD is hard, so if you come
152+
across articles that might be relevant for EventFlow, or even better, can
153+
point to specfic EventFlow functionality that might be done better, then
154+
please create an issue or ask in the Gitter chat
155+
135156
## License
136157

137158
```

RELEASE_NOTES.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
1-
### New in 0.12 (not released yet)
1+
### New in 0.13 (not released yet)
2+
3+
* Breaking: `EventFlowOptions.AddDefaults(...)` now also adds query handlers
4+
* New: Added an optional `Predicate<Type>` to the following option extension
5+
methods that scan an `Assembly`: `AddAggregateRoots(...)`,
6+
`AddCommandHandlers(...)`, `AddDefaults(...)`, `AddEventUpgraders(...)`,
7+
`AddEvents(...)`, `AddMetadataProviders(...)`, `AddQueryHandlers(...)` and
8+
`AddSubscribers(...)`
9+
* Fixed: `EventFlowOptions.AddAggregateRoots(...)` now prevents abstract
10+
classes from being registered when passing `IEnumerable<Type>`
11+
* Fixed: Events published to RabbitMQ are now in the right order for chains
12+
of subscribers, if `event A -> subscriber -> command -> aggregate -> event B`,
13+
then the order of published events to RabbitMQ was `event B` and then
14+
`event A`
15+
16+
### New in 0.12.891 (released 2015-09-04)
217

318
* Breaking: Aggregate root no longer have `Aggregate` removed from their
419
when name, i.e., the metadata property with key `aggregate_name` (or

Source/EventFlow.Tests/EventFlow.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<Reference Include="System.Xml" />
7070
</ItemGroup>
7171
<ItemGroup>
72+
<Compile Include="EventFlowTests.cs" />
7273
<Compile Include="IntegrationTests\BackwardCompatibilityTests.cs" />
7374
<Compile Include="IntegrationTests\ConfigurationTests.cs" />
7475
<Compile Include="IntegrationTests\DomainTests.cs" />
@@ -83,6 +84,7 @@
8384
<Compile Include="UnitTests\Commands\DistinctCommandTests.cs" />
8485
<Compile Include="UnitTests\Core\CircularBufferTests.cs" />
8586
<Compile Include="UnitTests\Core\IdentityTests.cs" />
87+
<Compile Include="UnitTests\Extensions\AggregatesExtensionsTests.cs" />
8688
<Compile Include="UnitTests\Extensions\StringExtensionsTests.cs" />
8789
<Compile Include="UnitTests\Queries\QueryProcessorTests.cs" />
8890
<Compile Include="UnitTests\ReadStores\ReadModelDomainEventApplierTests.cs" />
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015 Rasmus Mikkelsen
4+
// https://github.com/rasmus/EventFlow
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
7+
// this software and associated documentation files (the "Software"), to deal in
8+
// the Software without restriction, including without limitation the rights to
9+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10+
// the Software, and to permit persons to whom the Software is furnished to do so,
11+
// subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
23+
using System.Reflection;
24+
25+
namespace EventFlow.Tests
26+
{
27+
public static class EventFlowTests
28+
{
29+
public static Assembly Assembly { get; } = typeof(EventFlowTests).Assembly;
30+
}
31+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2015 Rasmus Mikkelsen
4+
// https://github.com/rasmus/EventFlow
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
7+
// this software and associated documentation files (the "Software"), to deal in
8+
// the Software without restriction, including without limitation the rights to
9+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10+
// the Software, and to permit persons to whom the Software is furnished to do so,
11+
// subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22+
23+
using System;
24+
using EventFlow.Aggregates;
25+
using EventFlow.Extensions;
26+
using EventFlow.TestHelpers.Aggregates.Test;
27+
using EventFlow.TestHelpers.Aggregates.Test.Events;
28+
using FluentAssertions;
29+
using NUnit.Framework;
30+
using EventFlow.Configuration.Registrations;
31+
using EventFlow.TestHelpers;
32+
using System.Collections.Generic;
33+
34+
namespace EventFlow.Tests.UnitTests.Extensions
35+
{
36+
public class AggregatesExtensionsTests
37+
{
38+
[Test]
39+
public void AbstractAggregateRootImplementationIsNotSelected()
40+
{
41+
// arrange
42+
var registry = new AutofacServiceRegistration();
43+
var sut = EventFlowOptions.New
44+
.UseServiceRegistration(registry);
45+
46+
// act
47+
sut.AddAggregateRoots(EventFlowTests.Assembly);
48+
49+
// assert
50+
registry.HasRegistrationFor<AbstractTestAggregate>().Should().Be(false);
51+
}
52+
53+
[Test]
54+
public void ClosedIAggregateRootImplementationIsSelected()
55+
{
56+
// arrange
57+
var registry = new AutofacServiceRegistration();
58+
var sut = EventFlowOptions.New
59+
.UseServiceRegistration(registry);
60+
61+
// act
62+
sut.AddAggregateRoots(EventFlowTestHelpers.Assembly);
63+
64+
// assert
65+
registry.HasRegistrationFor<TestAggregate>().Should().Be(true);
66+
}
67+
68+
[Test]
69+
public void AbstractAggregateRootImplementationIsRejected()
70+
{
71+
// arrange
72+
var registry = new AutofacServiceRegistration();
73+
var sut = EventFlowOptions.New
74+
.UseServiceRegistration(registry);
75+
76+
// act
77+
Action act = () => sut.AddAggregateRoots(new List<Type> { typeof(AbstractTestAggregate) } );
78+
79+
// assert
80+
act.ShouldThrow<ArgumentException>();
81+
}
82+
83+
[Test]
84+
public void NonIAggregateRootImplementationIsRejected()
85+
{
86+
// arrange
87+
var registry = new AutofacServiceRegistration();
88+
var sut = EventFlowOptions.New
89+
.UseServiceRegistration(registry);
90+
91+
// act
92+
Action act = () => sut.AddAggregateRoots(new List<Type> { typeof(TestId) });
93+
94+
// assert
95+
act.ShouldThrow<ArgumentException>();
96+
}
97+
98+
[Test]
99+
public void ClosedIAggregateRootImplementationIsAccepted()
100+
{
101+
// arrange
102+
var registry = new AutofacServiceRegistration();
103+
var sut = EventFlowOptions.New
104+
.UseServiceRegistration(registry);
105+
106+
// act
107+
Action act = () => sut.AddAggregateRoots(new List<Type> { typeof(LocalTestAggregate) });
108+
109+
// assert
110+
act.ShouldNotThrow<ArgumentException>();
111+
}
112+
}
113+
114+
public abstract class AbstractTestAggregate : AggregateRoot<TestAggregate, TestId>,
115+
IEmit<DomainErrorAfterFirstEvent>
116+
{
117+
public AbstractTestAggregate(TestId id) : base(id)
118+
{
119+
}
120+
121+
public void Apply(DomainErrorAfterFirstEvent aggregateEvent)
122+
{
123+
}
124+
}
125+
126+
public class LocalTestAggregate : AbstractTestAggregate
127+
{
128+
public LocalTestAggregate(TestId id) : base(id)
129+
{
130+
}
131+
}
132+
}

Source/EventFlow/EventFlowOptions.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using System;
2424
using System.Collections.Concurrent;
2525
using System.Collections.Generic;
26+
using System.Diagnostics;
2627
using EventFlow.Aggregates;
2728
using EventFlow.Configuration;
2829
using EventFlow.Configuration.Registrations;
@@ -43,9 +44,13 @@ public class EventFlowOptions
4344

4445
private readonly ConcurrentBag<Type> _aggregateEventTypes = new ConcurrentBag<Type>();
4546
private readonly EventFlowConfiguration _eventFlowConfiguration = new EventFlowConfiguration();
46-
private Lazy<IServiceRegistration> _lazyRegistrationFactory = new Lazy<IServiceRegistration>(() => new AutofacServiceRegistration());
47+
private Lazy<IServiceRegistration> _lazyRegistrationFactory = new Lazy<IServiceRegistration>(() => new AutofacServiceRegistration());
48+
private Stopwatch _stopwatch;
4749

48-
private EventFlowOptions() { }
50+
private EventFlowOptions()
51+
{
52+
_stopwatch = Stopwatch.StartNew();
53+
}
4954

5055
public EventFlowOptions ConfigureOptimisticConcurrentcyRetry(int retries, TimeSpan delayBeforeRetry)
5156
{
@@ -121,6 +126,10 @@ public IRootResolver CreateResolver(bool validateRegistrations = true)
121126
var eventDefinitionService = rootResolver.Resolve<IEventDefinitionService>();
122127
eventDefinitionService.LoadEvents(_aggregateEventTypes);
123128

129+
_stopwatch.Stop();
130+
var log = rootResolver.Resolve<ILog>();
131+
log.Debug("EventFlow configuration done in {0:0.000} seconds", _stopwatch.Elapsed.TotalSeconds);
132+
124133
return rootResolver;
125134
}
126135

Source/EventFlow/Extensions/EventFlowOptionsAggregatesExtensions.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,44 +40,47 @@ public static EventFlowOptions UseResolverAggregateRootFactory(
4040

4141
public static EventFlowOptions AddAggregateRoots(
4242
this EventFlowOptions eventFlowOptions,
43-
Assembly fromAssembly)
43+
Assembly fromAssembly,
44+
Predicate<Type> predicate = null)
4445
{
46+
predicate = predicate ?? (t => true);
4547
var aggregateRootTypes = fromAssembly
4648
.GetTypes()
47-
.Where(t => !t.IsAbstract && t.IsClosedTypeOf(typeof(IAggregateRoot<>)));
48-
eventFlowOptions.AddAggregateRoots(aggregateRootTypes);
49-
return eventFlowOptions;
49+
.Where(t => !t.IsAbstract)
50+
.Where(t => t.IsClosedTypeOf(typeof(IAggregateRoot<>)))
51+
.Where(t => predicate(t));
52+
return eventFlowOptions.AddAggregateRoots(aggregateRootTypes);
5053
}
5154

5255
public static EventFlowOptions AddAggregateRoots(
5356
this EventFlowOptions eventFlowOptions,
5457
params Type[] aggregateRootTypes)
5558
{
56-
eventFlowOptions.AddAggregateRoots((IEnumerable<Type>)aggregateRootTypes);
57-
return eventFlowOptions;
59+
return eventFlowOptions.AddAggregateRoots((IEnumerable<Type>)aggregateRootTypes);
5860
}
5961

6062
public static EventFlowOptions AddAggregateRoots(
6163
this EventFlowOptions eventFlowOptions,
6264
IEnumerable<Type> aggregateRootTypes)
6365
{
64-
var invalidateTypes = aggregateRootTypes
65-
.Where(t => !t.IsClosedTypeOf(typeof(IAggregateRoot<>)))
66-
.ToList();
67-
if (invalidateTypes.Any())
68-
{
69-
var names = string.Join(", ", invalidateTypes.Select(t => t.Name));
70-
throw new ArgumentException(string.Format(
71-
"Type(s) '{0}' do not implement IAggregateRoot<TIdentity>",
72-
names));
73-
}
66+
var aggregateRootTypeList = aggregateRootTypes.ToList();
7467

75-
foreach (var t in aggregateRootTypes)
68+
var invalidTypes = aggregateRootTypeList
69+
.Where(t => t.IsAbstract || !t.IsClosedTypeOf(typeof(IAggregateRoot<>)))
70+
.ToList();
71+
if (invalidTypes.Any())
7672
{
77-
eventFlowOptions.RegisterServices(sr => sr.RegisterType(t));
73+
var names = string.Join(", ", invalidTypes.Select(t => t.Name));
74+
throw new ArgumentException($"Type(s) '{names}' do not implement IAggregateRoot<TIdentity>");
7875
}
7976

80-
return eventFlowOptions;
77+
return eventFlowOptions.RegisterServices(sr =>
78+
{
79+
foreach (var t in aggregateRootTypeList)
80+
{
81+
sr.RegisterType(t);
82+
}
83+
});
8184
}
8285
}
8386
}

Source/EventFlow/Extensions/EventFlowOptionsCommandExtensions.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,22 @@ public static class EventFlowOptionsCommandExtensions
3232
{
3333
public static EventFlowOptions AddCommandHandlers(
3434
this EventFlowOptions eventFlowOptions,
35-
Assembly fromAssembly)
35+
Assembly fromAssembly,
36+
Predicate<Type> predicate = null)
3637
{
38+
predicate = predicate ?? (t => true);
3739
var commandHandlerTypes = fromAssembly
3840
.GetTypes()
39-
.Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof (ICommandHandler<,,>)));
40-
return eventFlowOptions
41-
.AddCommandHandlers(commandHandlerTypes);
41+
.Where(t => t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof (ICommandHandler<,,>)))
42+
.Where(t => predicate(t));
43+
return eventFlowOptions.AddCommandHandlers(commandHandlerTypes);
4244
}
4345

4446
public static EventFlowOptions AddCommandHandlers(
4547
this EventFlowOptions eventFlowOptions,
4648
params Type[] commandHandlerTypes)
4749
{
48-
return eventFlowOptions
49-
.AddCommandHandlers((IEnumerable<Type>) commandHandlerTypes);
50+
return eventFlowOptions.AddCommandHandlers((IEnumerable<Type>) commandHandlerTypes);
5051
}
5152

5253
public static EventFlowOptions AddCommandHandlers(

Source/EventFlow/Extensions/EventFlowOptionsDefaultExtensions.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2121
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222

23+
using System;
2324
using System.Reflection;
2425

2526
namespace EventFlow.Extensions
@@ -28,14 +29,16 @@ public static class EventFlowOptionsDefaultExtensions
2829
{
2930
public static EventFlowOptions AddDefaults(
3031
this EventFlowOptions eventFlowOptions,
31-
Assembly fromAssembly)
32+
Assembly fromAssembly,
33+
Predicate<Type> predicate = null)
3234
{
3335
return eventFlowOptions
34-
.AddEvents(fromAssembly)
35-
.AddCommandHandlers(fromAssembly)
36-
.AddMetadataProviders(fromAssembly)
37-
.AddSubscribers(fromAssembly)
38-
.AddEventUpgraders(fromAssembly);
36+
.AddEvents(fromAssembly, predicate)
37+
.AddCommandHandlers(fromAssembly, predicate)
38+
.AddMetadataProviders(fromAssembly, predicate)
39+
.AddSubscribers(fromAssembly, predicate)
40+
.AddEventUpgraders(fromAssembly, predicate)
41+
.AddQueryHandlers(fromAssembly, predicate);
3942
}
4043
}
4144
}

0 commit comments

Comments
 (0)