Created
September 1, 2010 10:16
-
-
Save ToJans/560498 to your computer and use it in GitHub Desktop.
combining CQRS, Event sourcing and BDD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace SimpleCQRS2.Framework.Services | |
{ | |
public class AggregateRootStore : IAggregateRootStore | |
{ | |
public IAggregateRoot GetAggregateRoot(Type aggregateRootType, Guid aggregateRootId) | |
{ | |
return GetStoredAggregateRoot(aggregateRootType, aggregateRootId).Instance; | |
} | |
public int GetAggregateRootVersion(Type aggregateRootType, Guid aggregateRootId) | |
{ | |
return GetStoredAggregateRoot(aggregateRootType, aggregateRootId).Version; | |
} | |
public void SaveOrUpdate(IAggregateRoot ar,int version) | |
{ | |
var x = GetStoredAggregateRoot(ar.GetType(),ar.AggregateRootId); | |
x.Instance = ar; | |
x.Version = version; | |
} | |
class StoredAggregateRoot | |
{ | |
public IAggregateRoot Instance { get; set; } | |
public int Version { get; set; } | |
public Type Type { | |
get { return Instance.GetType(); } | |
} | |
} | |
Dictionary<Type, Dictionary<Guid, StoredAggregateRoot>> ArStore = new Dictionary<Type, Dictionary<Guid, StoredAggregateRoot>>(); | |
private StoredAggregateRoot GetStoredAggregateRoot(Type aggregateRootType, Guid aggregateRootId) | |
{ | |
if (!ArStore.ContainsKey(aggregateRootType)) { | |
ArStore.Add(aggregateRootType, new Dictionary<Guid, StoredAggregateRoot>()); | |
} | |
if (!ArStore[aggregateRootType].ContainsKey(aggregateRootId)) { | |
IAggregateRoot instance = (IAggregateRoot)Activator.CreateInstance(aggregateRootType); | |
instance.AggregateRootId = aggregateRootId; | |
ArStore[aggregateRootType].Add(aggregateRootId, new StoredAggregateRoot { | |
Instance = instance, | |
Version = 0 | |
}); | |
} | |
return ArStore[aggregateRootType][aggregateRootId]; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using SimpleCQRS2.Example.Domain.Handlers; | |
using SimpleCQRS2.Example.Domain.Model; | |
using SimpleCQRS2.Example.Views; | |
using Aubergine.Model; | |
namespace SimpleCQRS2.Example.BDD | |
{ | |
public class BDDAppContext : SimpleCQRS2.Framework.BDD.CQRSFixture | |
{ | |
Dictionary<string, Guid> nameGuids = new Dictionary<string, Guid>(); | |
public BDDAppContext(){} | |
protected override IEnumerable<object> MessageHandlers { | |
get { | |
yield return new PositiveNumberHandler(); | |
yield return new SomeReadModelUpdater(); | |
} | |
} | |
[DSL(@"(?<name>nr\d+)")] | |
Guid GetGuid(string name) | |
{ | |
if (!nameGuids.ContainsKey(name)) nameGuids.Add(name,Guid.NewGuid()); | |
return nameGuids[name]; | |
} | |
[DSL(@"a positive number named (?<guid>nr\d+) was created")] | |
void NumberCreated(Guid guid) | |
{ | |
When(new PositiveNumber.Created() { AggregateRootId = guid}); | |
} | |
[DSL(@"(?<guid>nr\d+) was incremented")] | |
void WasIncremented(Guid guid) | |
{ | |
When(new PositiveNumber.WasIncremented() { AggregateRootId = guid }); | |
} | |
[DSL(@"the value of (?<guid>nr\d+) was changed")] | |
void WasChanged(Guid guid) | |
{ | |
When(new PositiveNumber.ValueHasChanged() { AggregateRootId = guid }); | |
} | |
[DSL(@"(?<guid>nr\d+) was decremented")] | |
void WasDecremented(Guid guid) | |
{ | |
When(new PositiveNumber.WasDecremented() { AggregateRootId = guid }); | |
} | |
[DSL(@"I decrement (?<guid>nr\d+)")] | |
void Decrement(Guid guid) | |
{ | |
When(new PositiveNumber.Decrement() { AggregateRootId = guid }); | |
} | |
[DSL(@"I increment (?<guid>nr\d+)")] | |
void Increment(Guid guid) | |
{ | |
When(new PositiveNumber.Increment() { AggregateRootId = guid }); | |
} | |
[DSL(@"it should have incremented (?<amount>\d+) times?")] | |
bool ShouldIncrement(int amount) | |
{ | |
return MyEventStore.All<PositiveNumber.WasIncremented>().Count() == amount; | |
} | |
[DSL(@"it should have decremented (?<amount>\d+) times?")] | |
bool ShouldDecrement(int amount) | |
{ | |
return MyEventStore.All<PositiveNumber.WasDecremented>().Count() == amount; | |
} | |
[DSL(@"it should have changed the value (?<amount>\d+) times?")] | |
bool ShouldChange(int amount) | |
{ | |
return MyEventStore.All<PositiveNumber.ValueHasChanged>().Count() == amount; | |
} | |
[DSL(@"the value of (?<guid>nr\d+) should be (?<value>\d+)")] | |
bool ValueShouldBe(Guid guid,int value) | |
{ | |
var ar = (PositiveNumber)MyArStore.GetAggregateRoot(typeof(PositiveNumber),guid); | |
return ar.Value == value; | |
} | |
[DSL(@"the screen value for (?<guid>nr\d+) should be (?<value>\d+)")] | |
bool ScreenValueShouldBe(Guid guid,int value) | |
{ | |
var mu = MyIOC.Resolve<SomeReadModelUpdater>().First(); | |
return mu.Values[guid] == value ; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace SimpleCQRS2.Framework.Services | |
{ | |
public class CQRSCommandBus : ICommandBus | |
{ | |
public CQRSCommandBus(IAnIOC IOC,IEventStore evs,IAggregateRootStore agrs) | |
{ | |
this.IOC = IOC; | |
this.agrs = agrs; | |
this.evs = evs; | |
} | |
IAnIOC IOC = null; | |
IEventStore evs = null; | |
IAggregateRootStore agrs=null; | |
public static IEnumerable<Type> GetMessageHandlerInterfaces(Type T) | |
{ | |
foreach (var i in T.GetInterfaces().Where(t => t.IsGenericType)) { | |
if (i.GetGenericTypeDefinition() == typeof(IMessageHandler<,>)) | |
yield return i; | |
} | |
} | |
public void HandleCommand(ICommand command) | |
{ | |
HandleMessage(command, false); | |
} | |
public void RunEvents(IAggregateRoot aggregateRoot) | |
{ | |
while (true) { | |
var version = agrs.GetAggregateRootVersion(aggregateRoot.GetType(),aggregateRoot.AggregateRootId); | |
var e = evs.NextEvent(aggregateRoot.GetType(),aggregateRoot.AggregateRootId,version); | |
if (e == null) | |
break; | |
HandleMessage(e, true); | |
} | |
} | |
void HandleMessage(IMessage message, bool isreplay) | |
{ | |
var gt = typeof(IMessageHandler<,>).MakeGenericType(new Type[] { message.AggregateRootType,message.GetType() }); | |
var handlers = IOC.Resolve(gt); | |
if (! isreplay && !handlers.Any()) | |
throw new Exception("Type unknown; no handlers available:" + message.GetType().Name); | |
List<IEvent> events = new List<IEvent>(); | |
var aggregateRoot = agrs.GetAggregateRoot(message.AggregateRootType, message.AggregateRootId); | |
if (!isreplay) | |
RunEvents(aggregateRoot); | |
var version = agrs.GetAggregateRootVersion(message.AggregateRootType, message.AggregateRootId); | |
foreach (var handler in handlers) | |
{ | |
var mi = handler.GetType().GetMethod("Handle", new Type[] { | |
message.GetType(), | |
message.AggregateRootType | |
}); | |
var result = mi.Invoke(handler, new object[] { | |
message, | |
aggregateRoot | |
}); | |
// makes sure ienumerable gets consumed | |
events.AddRange((IEnumerable<IEvent>)result); | |
} | |
var evt = message as IEvent; | |
if (evt!=null) | |
{ | |
if ( !isreplay) | |
evs.Save(evt); | |
agrs.SaveOrUpdate(aggregateRoot,version+1); | |
} | |
if (!isreplay) | |
{ | |
foreach (var e in events) | |
{ | |
HandleMessage(e, isreplay); | |
} | |
} | |
} | |
public void HandleEvent(IEvent e) | |
{ | |
HandleMessage(e,true); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using NUnit.Framework; | |
using SimpleCQRS2.Framework.Services; | |
namespace SimpleCQRS2.Framework.BDD | |
{ | |
public abstract class CQRSFixture | |
{ | |
protected IAnIOC MyIOC; | |
protected ICommandBus MyMessageBus; | |
protected IEventStore MyEventStore; | |
protected IAggregateRootStore MyArStore; | |
protected abstract IEnumerable<object> MessageHandlers {get;} | |
protected CQRSFixture() | |
{ | |
MyIOC = new IOCStub(); | |
MyArStore = new AggregateRootStore(); | |
MyEventStore = new EventStore(); | |
MyMessageBus = new CQRSCommandBus(MyIOC,MyEventStore,MyArStore); | |
foreach (var inst in MessageHandlers) | |
{ | |
var t = inst.GetType(); | |
MyIOC.Register(t, inst); | |
foreach (var it in CQRSCommandBus.GetMessageHandlerInterfaces(t)) | |
MyIOC.Register(it, inst); | |
} | |
} | |
public void Given(IEvent Anevent) | |
{ | |
MyMessageBus.HandleEvent(Anevent); | |
} | |
public void When(ICommand c) | |
{ | |
MyMessageBus.HandleCommand(c); | |
} | |
public void When(IEvent e) | |
{ | |
MyMessageBus.HandleEvent(e); | |
} | |
public CQRSFixture ThenEvents<T>(Predicate<IEnumerable<T>> pred) where T:IEvent | |
{ | |
Assert.True(pred(MyEventStore.All<T>())); | |
return this; | |
} | |
public CQRSFixture ThenAggregateRoot<T>(Guid aggregateRootId,Predicate<T> pred) where T:IAggregateRoot | |
{ | |
var ar = (T)MyArStore.GetAggregateRoot(typeof(T),aggregateRootId); | |
MyMessageBus.RunEvents(ar); | |
Assert.True(pred(ar)); | |
return this; | |
} | |
public CQRSFixture ThenServices<T>(Predicate<IEnumerable<T>> pred) | |
{ | |
Assert.True(pred(MyIOC.Resolve<T>())); | |
return this ; | |
} | |
public CQRSFixture ThenService<T>(Predicate<T> pred) | |
{ | |
Assert.True(pred(MyIOC.Resolve<T>().First())); | |
return this ; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace SimpleCQRS2.Framework.Services | |
{ | |
public class EventStore : IEventStore | |
{ | |
public void Save(IEvent Event) | |
{ | |
var lastevent = Store.Where(x=>x.Event.AggregateRootId == Event.AggregateRootId).LastOrDefault(); | |
var version = lastevent == null ? 0 : lastevent.Version+1; | |
Store.Add(new StoredEvent { | |
Event = Event, | |
Version = version | |
}); | |
} | |
public IEvent NextEvent(Type T,Guid aggregateRootId, int version) | |
{ | |
return Store | |
.Where(x => | |
x.Event.AggregateRootType == T && | |
x.Event.AggregateRootId == aggregateRootId && | |
x.Version ==version ) | |
.Select(x => x.Event) | |
.FirstOrDefault(); | |
} | |
public IEnumerable<T> All<T>() where T : IEvent | |
{ | |
return Store.Select(x => x.Event).OfType<T>(); | |
} | |
List<StoredEvent> Store = new List<StoredEvent>(); | |
class StoredEvent | |
{ | |
public IEvent Event { get; set; } | |
public int Version { get; set; } | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// BDD fixtures when using CQRS/Eventsourcing = win | |
// | |
// ToJans@twitter | |
// | |
// To run | |
// - open a command window | |
// - go to the build folder (bin/debug) | |
// - type "consolerunner example\*.txt" for normal output | |
// - type "consolerunner example\*.txt -html > output.html" for output to a file named output.html | |
// - type "consolerunner -h" for help | |
// | |
// check out the BDDAppContext source, it is practicly a 1 to 1 conversion | |
Define the appcontext | |
using SimpleCQRS2.Example.BDD.BDDAppContext | |
from SimpleCQRS2.DLL | |
Story This is the proof of concept that BDD works perfectly with CQRS/eventsourcing | |
is about the appcontext | |
As a developer | |
I want to be able to use CQRS/eventsourcing for this example of a positive number | |
In order to show how easy it is to set up BDD contexts | |
Scenario [Integration]Decrement command does not work/raise events when the value is zero | |
Given a positive number named nr1 was created | |
When I decrement nr1 | |
And I increment nr1 | |
And I increment nr1 | |
And I decrement nr1 | |
Then it should have incremented 2 times | |
And it should have decremented 1 time | |
And it should have changed the value 3 times | |
Scenario [AggregateRoot]When raising an increment or decrement event on a positive number, it should modify the value | |
When a positive number named nr1 was created | |
And a positive number named nr2 was created | |
And nr1 was incremented | |
And nr1 was incremented | |
And nr2 was incremented | |
And nr2 was incremented | |
And nr2 was decremented | |
Then the value of nr1 should be 2 | |
And the value of nr2 should be 1 | |
Scenario [Readmodel]When raising a valuechanged event, it should modify the readmodel's matching values | |
Given a positive number named nr1 was created | |
And a positive number named nr2 was created | |
And nr1 was incremented | |
And nr1 was incremented | |
And nr2 was incremented | |
When the value of nr1 was changed | |
And the value of nr2 was changed | |
Then the screen value for nr1 should be 2 | |
And the screen value for nr2 should be 1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace SimpleCQRS2.Framework | |
{ | |
// interfaces | |
public interface IHasAggregateRootId | |
{ | |
Guid AggregateRootId { get;set;} | |
} | |
public interface IAggregateRoot : IHasAggregateRootId | |
{ | |
} | |
public interface IMessage:IHasAggregateRootId | |
{ | |
Type AggregateRootType { get; set; } | |
} | |
public interface IMessage<TAggregate> | |
: IMessage where TAggregate : IAggregateRoot | |
{ | |
} | |
public interface IMessageHandler<TAggregate,TMessage> | |
where TAggregate:IAggregateRoot | |
where TMessage : IMessage<TAggregate> | |
{ | |
IEnumerable<IEvent> Handle(TMessage message, TAggregate aggregateRoot); | |
} | |
public interface IEvent : IMessage {} | |
public interface ICommand : IMessage {} | |
public interface ICommandBus | |
{ | |
void HandleCommand(ICommand command); | |
void RunEvents(IAggregateRoot aggregateRoot); | |
void HandleEvent(IEvent e); | |
} | |
public interface IAggregateRootStore | |
{ | |
IAggregateRoot GetAggregateRoot(Type aggregateRootType, Guid aggregateRootId); | |
int GetAggregateRootVersion(Type aggregateRootType, Guid aggregateRootId); | |
void SaveOrUpdate(IAggregateRoot ar,int version); | |
} | |
public interface IEventStore | |
{ | |
// save should set the version as well | |
void Save(IEvent Event); | |
IEvent NextEvent(Type t,Guid AggregateRootId,int version); | |
IEnumerable<T> All<T>() where T:IEvent; | |
} | |
public interface IAnIOC | |
{ | |
void Register(Type T, object instance); | |
IEnumerable<object> Resolve(Type T); | |
IEnumerable<T> Resolve<T>(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace SimpleCQRS2.Framework.Services | |
{ | |
public class IOCStub : IAnIOC | |
{ | |
public IEnumerable<object> Resolve(Type T) | |
{ | |
return instances[T]; | |
} | |
public void Register(Type T, object instanceGetter) | |
{ | |
if (!instances.ContainsKey(T)) | |
instances.Add(T, new List<object>()); | |
instances[T].Add(instanceGetter); | |
} | |
public IEnumerable<T> Resolve<T>() | |
{ | |
foreach (var i in Resolve(typeof(T))) | |
yield return (T)i; | |
} | |
Dictionary<Type, List<object>> instances = new Dictionary<Type, List<object>>(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// simple CQRS | |
// attempt to understand CQRS the way it is supposed to work, | |
// and set it up for easy BDD testing | |
// tojans@twitter | |
// this is a running test | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using NUnit.Framework; | |
using SimpleCQRS2.Example.Domain.Handlers; | |
using SimpleCQRS2.Example.Domain.Model; | |
using SimpleCQRS2.Example.Views; | |
using SimpleCQRS2.Framework.BDD; | |
namespace SimpleCQRS2.Example.BDD | |
{ | |
[TestFixture()] | |
public class NUnitTest : CQRSFixture | |
{ | |
protected override IEnumerable<object> MessageHandlers { | |
get { | |
yield return new PositiveNumberHandler(); | |
yield return new SomeReadModelUpdater(); | |
} | |
} | |
[Test()] | |
public void IntegrationTest() | |
{ | |
var anotherguid = Guid.NewGuid(); | |
var aguid = Guid.NewGuid(); | |
Given(new PositiveNumber.Created() {AggregateRootId = aguid }); | |
Given(new PositiveNumber.Created() {AggregateRootId = anotherguid }); | |
Given(new PositiveNumber.WasIncremented() {AggregateRootId = aguid }); | |
Given(new PositiveNumber.WasIncremented() {AggregateRootId = aguid }); | |
When(new PositiveNumber.Decrement(){ AggregateRootId = anotherguid }); | |
When(new PositiveNumber.Increment() { AggregateRootId = anotherguid }); | |
When(new PositiveNumber.Increment() { AggregateRootId = anotherguid }); | |
When(new PositiveNumber.Decrement(){ AggregateRootId = anotherguid }); | |
ThenEvents<PositiveNumber.WasIncremented>(x=>x.Count()==4); | |
ThenEvents<PositiveNumber.WasDecremented>(x=>x.Count() == 1); | |
ThenEvents<PositiveNumber.ValueHasChanged>(x=>x.Count() == 3); | |
ThenAggregateRoot<PositiveNumber>(aguid,pn=>pn.Value == 2); | |
ThenAggregateRoot<PositiveNumber>(anotherguid,pn=>pn.Value == 1); | |
ThenService<SomeReadModelUpdater>( s=>s.Values[anotherguid] == 1); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Aubergine Console Runner - Core bvba - Tom Janssens 2009 | |
Parsing files | |
Processing file(s) : Example\Integration.txt | |
Parsing file : C:\Tom Hotouch\CQRS\gist-560498\bin\Debug\Example\Integration.txt | |
Running Tests | |
Story This is the proof of concept that BDD works perfectly with CQRS/eventsourcing =>OK | |
Context the appcontext =>OK | |
Scenario [Integration]Decrement command does not work/raise events when the value is zero =>OK | |
Given a positive number named nr1 was created =>OK | |
When I decrement nr1 =>OK | |
When I increment nr1 =>OK | |
When I increment nr1 =>OK | |
When I decrement nr1 =>OK | |
Then it should have incremented 2 times =>OK | |
Then it should have decremented 1 time =>OK | |
Then it should have changed the value 3 times =>OK | |
Scenario [AggregateRoot]When raising an increment or decrement event on a positive number, it should modify the value =>OK | |
When a positive number named nr1 was created =>OK | |
When a positive number named nr2 was created =>OK | |
When nr1 was incremented =>OK | |
When nr1 was incremented =>OK | |
When nr2 was incremented =>OK | |
When nr2 was incremented =>OK | |
When nr2 was decremented =>OK | |
Then the value of nr1 should be 2 =>OK | |
Then the value of nr2 should be 1 =>OK | |
Scenario [Readmodel]When raising a valuechanged event, it should modify the readmodel's matching values =>OK | |
Given a positive number named nr1 was created =>OK | |
Given a positive number named nr2 was created =>OK | |
Given nr1 was incremented =>OK | |
Given nr1 was incremented =>OK | |
Given nr2 was incremented =>OK | |
When the value of nr1 was changed =>OK | |
When the value of nr2 was changed =>OK | |
Then the screen value for nr1 should be 2 =>OK | |
Then the screen value for nr2 should be 1 =>OK |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using SimpleCQRS2.Framework; | |
using SimpleCQRS2.Example.Domain.Model; | |
namespace SimpleCQRS2.Example.Domain.Model | |
{ // domain model | |
public partial class PositiveNumber : IAggregateRoot | |
{ | |
public int Value = 0; | |
public Guid AggregateRootId { get; set; } | |
} | |
// AR messages | |
public partial class PositiveNumber | |
{ | |
public abstract class Message : IMessage<PositiveNumber> | |
{ | |
public Guid AggregateRootId { get; set; } | |
public Type AggregateRootType { get; set; } | |
public Message() | |
{ | |
AggregateRootType = typeof(PositiveNumber); | |
} | |
} | |
public class Create: Message, ICommand {}; | |
public class Created : Message, IEvent {}; | |
public class Increment : Message, ICommand {} | |
public class Decrement : Message, ICommand {} | |
public class WasIncremented : Message, IEvent {} | |
public class WasDecremented : Message, IEvent {} | |
public class ValueHasChanged : Message, IEvent {} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.Remoting.Messaging; | |
using SimpleCQRS2.Framework; | |
using SimpleCQRS2.Example.Domain.Model; | |
namespace SimpleCQRS2.Example.Domain.Handlers | |
{ // domain services / handlers | |
public class PositiveNumberHandler | |
: IMessageHandler<PositiveNumber,PositiveNumber.Increment> | |
, IMessageHandler<PositiveNumber,PositiveNumber.WasIncremented> | |
, IMessageHandler<PositiveNumber,PositiveNumber.Decrement> | |
, IMessageHandler<PositiveNumber,PositiveNumber.WasDecremented> | |
, IMessageHandler<PositiveNumber,PositiveNumber.Create> | |
, IMessageHandler<PositiveNumber,PositiveNumber.Created> | |
{ | |
public IEnumerable<IEvent> Handle(PositiveNumber.Increment command, PositiveNumber ar) | |
{ | |
yield return new PositiveNumber.WasIncremented { AggregateRootId = ar.AggregateRootId }; | |
} | |
public IEnumerable<IEvent> Handle(PositiveNumber.Decrement command, PositiveNumber ar) | |
{ | |
if (ar.Value > 0) { | |
yield return new PositiveNumber.WasDecremented { AggregateRootId = ar.AggregateRootId }; | |
} | |
} | |
public IEnumerable<IEvent> Handle(PositiveNumber.WasIncremented evt, PositiveNumber ar) | |
{ | |
ar.Value++; | |
yield return new PositiveNumber.ValueHasChanged { AggregateRootId = ar.AggregateRootId }; | |
} | |
public IEnumerable<IEvent> Handle(PositiveNumber.WasDecremented evt, PositiveNumber ar) | |
{ | |
ar.Value--; | |
yield return new PositiveNumber.ValueHasChanged { AggregateRootId = ar.AggregateRootId }; | |
} | |
public IEnumerable<IEvent> Handle(PositiveNumber.Create message, PositiveNumber aggregateRoot) | |
{ | |
yield return new PositiveNumber.Created() {AggregateRootId = Guid.NewGuid() }; | |
} | |
public IEnumerable<IEvent> Handle(PositiveNumber.Created message, PositiveNumber aggregateRoot) | |
{ | |
aggregateRoot.Value = 0; | |
yield return new PositiveNumber.ValueHasChanged() { AggregateRootId = aggregateRoot.AggregateRootId }; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using SimpleCQRS2.Framework; | |
using SimpleCQRS2.Example.Domain.Model; | |
namespace SimpleCQRS2.Example.Views | |
{ | |
public class SomeReadModelUpdater | |
: IMessageHandler<PositiveNumber,PositiveNumber.ValueHasChanged> | |
{ | |
public Dictionary<Guid, int> Values = new Dictionary<Guid, int>(); | |
public IEnumerable<IEvent> Handle(PositiveNumber.ValueHasChanged evt, PositiveNumber aggregateRoot) | |
{ | |
Values[evt.AggregateRootId] = (aggregateRoot as PositiveNumber).Value; | |
yield break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment