original code snippets from GregYoung 8 CQRS Class
Code snippets from GregYoung 8 CQRS Class - YouTube
public class DeactivateInventoryItemCommand {public readonly Guid InventoryItemId;public readonly string Comment;public DeactivateInventoryItemCommand (Guid id, string comment) {InventoryItemId = id;Comment = comment;}void DeactivateInventoryItem(Guid, string comment)
CommandHandler
contains no logic, logic is in domain object
delegates to domain object
public class DeactivateInventoryItemHandler : Handles<DeactivateInventoryItem> {public DeactivateInventoryItemHandler(InventoryItemRepository rep){}void Handle(DeactivateInventoryItem cmd) {var item = repository.GetById(cmd.Id);item.Deactivate(cmd.Comment);}}
Application Services
cross-cutting concerns (logging, authentication)
public class TransactionalHandler<T> : Handles<T> where T:Message {private Handles<T> next;public TransactionalHandler(Handles<T> Next) {next = Next;}public Handle(T cmd) {using(new UnitOfWork()) {next.Handle(cmd);}}}public class LoggingHandler<T> : Handles<T> where T:Message {private Handles<T> next;public TransactionalHandler(Handles<T> Next) {next = Next;}public Handle(T cmd) {using(new UnitOfWork()) {next.Handle(cmd);}}}var handler = new TransactionalHandler<DeactiveateInventoryItemCommand>(new LoggingHandler<DeactiveateInventoryItemCommand>(new DeactiveateInventoryItemHandler()))CommandHandler only 1[RequiresPermission("Admin")][Transactional][LogsTo("C:\\foo.txt")]public class DeactivateInventoryItemHandler : Handles<DeactivateInventoryItem> {public DeactivateInventoryItemHandler(InventoryItemRepository rep){}void Handle(DeactivateInventoryItem cmd) {var item = repository.GetById(cmd.Id);item.Deactivate(cmd.Comment);}}command and eventpublic class DeactivateInventoryItem {public readonly Guid InventoryItemId;public readonly string Comment;public DeactivateInventoryItemCommand (Guid id, string comment) {InventoryItemId = id;Comment = comment;}public class InventoryItemDeactivated {public readonly Guid InventoryItemId;public readonly string Comment;public InventoryItemDeactivated (Guid id, string comment) {InventoryItemId = id;Comment = comment;}EventHandler[Transactional]public class DeactivatedEventHandler : Handles <InventoryItemDeactivatedEvent> {public void Handle(InventoryItemDeactivatedEvent e) {INSERT INTO FOO () VALUES e.cjjd e.ccc}}AggregateRootpublic class InventoryItem : AggregateRoot {WarehouseLocationInformation info;bool activated;public InventoryItem() {RegisterHandler(typeof(DeactivatedEvent), ApplyDeactivatedEvent);RegisterHandler(typeof(WarehouseLocationInformationRegistered), ApplyWareh...Registered);}private void Apply(DeactivatedEvent e) {activated = false;}private void Apply(WarehouseLocationInformationRegistered e) {info = new WarehouseLocationInformation(e.PhysicalLocation, e.GeoLocation, e.PaymentRate);}private void Deactivate() {if(!activated) throw new InvalidOperationException();if(comment==null) throw ...();ApplyEvent(new InventoryDeactivatedEvent(id));}}public class AggregateRoot : IAggregateRoot {private Dictionary<Type, appliesEvent> lookup = new Dictionary<Type, appliesEvent>();protected void RegisterHandler<T>(appliesEvent handler) {lookup.add(typeof(T), handler);}public IEnumerable<Event> GetChanges() {foreach(Event e in events) yield return e;events.Clear();}protected void ApplyEvent(Event e) { ApplyEvent(e, true); }private void ApplyEvent(Event e, bool add) {appliesEvent handler;if(!lookup.TryGetValue(e.getType(), out handler)) {throw new HandlerNotFoundException();}handler(e);if(add) UnitOfWork.GetCurrent().Enregister(e);}public void LoadFromHistory(IEnumerable<Event> events) {foreach(Event e in events) {ApplyEvent(e, false);}}}InventoryItemDeactivatedEventpublic class InventoryItemDeactivatedEvent : Event {public readonly Guid Id;public InventoryItemDeactivatedEvent (Guid id) {Id = id;}Test[TestFixture]public class when_an_inventory_item_is_deactivated : AggregateRootTestFixture<InventoryItem> {private Guid id = Guid.newGuid();protected override IEnumerable<Event> Given() {yield return New.InventoryItemCreated.WithName("Test");}protected override void When() {sut.Deactivate();}[Test]public void should_publish_deactivated_Event() {Assert.Inconclusive();}[Test]public void should_publish_event_with_correct_id() {Assert.AreEquel(id, ((InventoryDeactivatedEvent) events[0]).AggregateId);}}public abstract class AggregateRootTestFixture<T> : where T:IAggregateRoot, new() {protected IAggregateRoot root;protected Exception caught = null;protected T sut;protected List<Event> events;protected abstract IEnumerable<Event> Given();protected abstract void When();[SetUp]public void Setup() {root = new T();root.LoadFromHistory(Given());try{When();events = new List<Event>(root.GetChanges());} catch(Exception Ex) {caught = Ex;}}}bddGiven a set of eventswhen I issue a commandexpect a set of eventsGivenan inventory item createdWhen Ideactivate inventory itemexpectinventory item deactivatedGivenan inventory item createdan inventory item deactivatedWhen Ideactivate inventory itemexpectinvalidoperation exceptionViewpublic class InventoryCountView : Handles<InventoryAddedEvent>, Handles<InventoryItemRemovedEvent>, Handles<InventoryItemCreatedEvent>public void Handle(InventoryItemAddedEvent) {update InventoryCountView set currentcount = currentcount + e.Count}public void Handle(InventoryItemCreatedEvent e) {insert into InventoryCountView currentcount values 0}Versioningpublic class InventoryItemDeactivatedEvent : Event {public readonly Guid Id;public InventoryItemDeactivatedEvent (Guid id) {Id = id;}}public class InventoryItemDeactivatedEvent_v2 : Event {public readonly Guid Id;public readonly string Comment;public InventoryItemDeactivatedEvent (Guid id, string comment) {Id = id;Comment = commment;}}public class InventoryItemDeactivatedEvent_v3 : Event {T ConvertTo<T,V>(V v) where T:Message, V:MessageDeactivatedEvent_v2 ConvertTo(DeactivatedEvent v) {return new DeactivatedEvent_v2(v.Id, null);}