Refactoring Domain Events so it is clear and differenciated versus Integration Events

This commit is contained in:
Cesar De la Torre 2017-03-16 18:52:02 -07:00
parent 6f6f09e11e
commit b9c1778d9d
12 changed files with 50 additions and 45 deletions

View File

@ -6,22 +6,22 @@ using Ordering.Domain.Events;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ordering.API.Application.EventHandlers namespace Ordering.API.Application.DomainEventHandlers
{ {
public class OrderCreatedEventHandler : IAsyncNotificationHandler<OrderCreated> public class OrderCreatedDomainEventHandler : IAsyncNotificationHandler<OrderCreatedDomainEvent>
{ {
private readonly ILoggerFactory _logger; private readonly ILoggerFactory _logger;
private readonly IBuyerRepository<Buyer> _buyerRepository; private readonly IBuyerRepository<Buyer> _buyerRepository;
private readonly IIdentityService _identityService; private readonly IIdentityService _identityService;
public OrderCreatedEventHandler(ILoggerFactory logger, IBuyerRepository<Buyer> buyerRepository, IIdentityService identityService) public OrderCreatedDomainEventHandler(ILoggerFactory logger, IBuyerRepository<Buyer> buyerRepository, IIdentityService identityService)
{ {
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository)); _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService)); _identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
} }
public async Task Handle(OrderCreated orderNotification) public async Task Handle(OrderCreatedDomainEvent orderNotification)
{ {
var cardTypeId = orderNotification.CardTypeId != 0 ? orderNotification.CardTypeId : 1; var cardTypeId = orderNotification.CardTypeId != 0 ? orderNotification.CardTypeId : 1;
@ -46,7 +46,7 @@ namespace Ordering.API.Application.EventHandlers
await _buyerRepository.UnitOfWork await _buyerRepository.UnitOfWork
.SaveEntitiesAsync(); .SaveEntitiesAsync();
_logger.CreateLogger(nameof(OrderCreatedEventHandler)).LogTrace($"A new payment method has been successfully added for orderId: {orderNotification.Order.Id}."); _logger.CreateLogger(nameof(OrderCreatedDomainEventHandler)).LogTrace($"A new payment method has been successfully added for orderId: {orderNotification.Order.Id}.");
} }
} }

View File

@ -5,19 +5,19 @@ using Ordering.Domain.Events;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ordering.API.Application.EventHandlers namespace Ordering.API.Application.DomainEventHandlers
{ {
public class PaymentMethodCheckedEventHandler : IAsyncNotificationHandler<PaymentMethodChecked> public class PaymentMethodCheckedDomainEventHandler : IAsyncNotificationHandler<PaymentMethodCheckedDomainEvent>
{ {
private readonly IOrderRepository<Order> _orderRepository; private readonly IOrderRepository<Order> _orderRepository;
private readonly ILoggerFactory _logger; private readonly ILoggerFactory _logger;
public PaymentMethodCheckedEventHandler(IOrderRepository<Order> orderRepository, ILoggerFactory logger) public PaymentMethodCheckedDomainEventHandler(IOrderRepository<Order> orderRepository, ILoggerFactory logger)
{ {
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
} }
public async Task Handle(PaymentMethodChecked paymentMethodNotification) public async Task Handle(PaymentMethodCheckedDomainEvent paymentMethodNotification)
{ {
var orderToUpdate = await _orderRepository.GetAsync(paymentMethodNotification.OrderId); var orderToUpdate = await _orderRepository.GetAsync(paymentMethodNotification.OrderId);
orderToUpdate.SetBuyerId(paymentMethodNotification.Buyer.Id); orderToUpdate.SetBuyerId(paymentMethodNotification.Buyer.Id);
@ -26,7 +26,7 @@ namespace Ordering.API.Application.EventHandlers
await _orderRepository.UnitOfWork await _orderRepository.UnitOfWork
.SaveEntitiesAsync(); .SaveEntitiesAsync();
_logger.CreateLogger(nameof(PaymentMethodCheckedEventHandler)) _logger.CreateLogger(nameof(PaymentMethodCheckedDomainEventHandler))
.LogTrace($"Order with Id: {paymentMethodNotification.OrderId} has been successfully updated with a new payment method id: { paymentMethodNotification.Payment.Id }"); .LogTrace($"Order with Id: {paymentMethodNotification.OrderId} has been successfully updated with a new payment method id: { paymentMethodNotification.Payment.Id }");
} }
} }

View File

@ -3,7 +3,7 @@ using Autofac.Core;
using MediatR; using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators;
using Ordering.API.Application.EventHandlers; using Ordering.API.Application.DomainEventHandlers;
using Ordering.Domain.Events; using Ordering.Domain.Events;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -24,7 +24,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
.Select(i => new KeyedService("IAsyncRequestHandler", i))); .Select(i => new KeyedService("IAsyncRequestHandler", i)));
builder builder
.RegisterAssemblyTypes(typeof(OrderCreatedEventHandler).GetTypeInfo().Assembly) .RegisterAssemblyTypes(typeof(OrderCreatedDomainEventHandler).GetTypeInfo().Assembly)
.Where(t => t.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>))) .Where(t => t.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
.AsImplementedInterfaces(); .AsImplementedInterfaces();

View File

@ -33,7 +33,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
if (existingPayment != null) if (existingPayment != null)
{ {
AddEvent(new PaymentMethodChecked(this, existingPayment, orderId)); AddDomainEvent(new PaymentMethodCheckedDomainEvent(this, existingPayment, orderId));
return existingPayment; return existingPayment;
} }
else else
@ -41,7 +41,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
var payment = new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration); var payment = new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration);
_paymentMethods.Add(payment); _paymentMethods.Add(payment);
AddEvent(new PaymentMethodChecked(this, payment, orderId)); AddDomainEvent(new PaymentMethodCheckedDomainEvent(this, payment, orderId));
return payment; return payment;
} }
} }

View File

@ -51,7 +51,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.InProcess.Id; _orderStatusId = OrderStatus.InProcess.Id;
_orderDate = DateTime.UtcNow; _orderDate = DateTime.UtcNow;
Address = address; Address = address;
AddCreatedOrderEvent(cardTypeId, cardNumber,
// Add the OrderCreatedEvent to the domain events collection
// to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ]
AddOrderCreatedDomainEvent(cardTypeId, cardNumber,
cardSecurityNumber, cardHolderName, cardExpiration); cardSecurityNumber, cardHolderName, cardExpiration);
} }
@ -93,14 +96,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_buyerId = id; _buyerId = id;
} }
private void AddCreatedOrderEvent(int cardTypeId, string cardNumber, private void AddOrderCreatedDomainEvent(int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) string cardSecurityNumber, string cardHolderName, DateTime cardExpiration)
{ {
var @orderCreatedEvent = new OrderCreated( var orderCreatedDomainEvent = new OrderCreatedDomainEvent(
this, cardTypeId, cardNumber, cardSecurityNumber, this, cardTypeId, cardNumber, cardSecurityNumber,
cardHolderName, cardExpiration); cardHolderName, cardExpiration);
AddEvent(@orderCreatedEvent); AddDomainEvent(orderCreatedDomainEvent);
} }
} }
} }

View File

@ -9,7 +9,7 @@ namespace Ordering.Domain.Events
/// <summary> /// <summary>
/// Event used when an order is created /// Event used when an order is created
/// </summary> /// </summary>
public class OrderCreated public class OrderCreatedDomainEvent
: IAsyncNotification : IAsyncNotification
{ {
public int CardTypeId { get; private set; } public int CardTypeId { get; private set; }
@ -19,7 +19,7 @@ namespace Ordering.Domain.Events
public DateTime CardExpiration { get; private set; } public DateTime CardExpiration { get; private set; }
public Order Order { get; private set; } public Order Order { get; private set; }
public OrderCreated(Order order, public OrderCreatedDomainEvent(Order order,
int cardTypeId, string cardNumber, int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, string cardSecurityNumber, string cardHolderName,
DateTime cardExpiration) DateTime cardExpiration)

View File

@ -6,14 +6,14 @@ using System.Text;
namespace Ordering.Domain.Events namespace Ordering.Domain.Events
{ {
public class PaymentMethodChecked public class PaymentMethodCheckedDomainEvent
: IAsyncNotification : IAsyncNotification
{ {
public Buyer Buyer { get; private set; } public Buyer Buyer { get; private set; }
public PaymentMethod Payment { get; private set; } public PaymentMethod Payment { get; private set; }
public int OrderId { get; private set; } public int OrderId { get; private set; }
public PaymentMethodChecked(Buyer buyer, PaymentMethod payment, int orderId) public PaymentMethodCheckedDomainEvent(Buyer buyer, PaymentMethod payment, int orderId)
{ {
Buyer = buyer; Buyer = buyer;
Payment = payment; Payment = payment;

View File

@ -10,7 +10,7 @@
int? _requestedHashCode; int? _requestedHashCode;
int _Id; int _Id;
private List<IAsyncNotification> _events; private List<IAsyncNotification> _domainEvents;
public virtual int Id public virtual int Id
{ {
@ -24,17 +24,17 @@
} }
} }
public List<IAsyncNotification> Events => _events; public List<IAsyncNotification> DomainEvents => _domainEvents;
public void AddEvent(IAsyncNotification eventItem) public void AddDomainEvent(IAsyncNotification eventItem)
{ {
_events = _events ?? new List<IAsyncNotification>(); _domainEvents = _domainEvents ?? new List<IAsyncNotification>();
_events.Add(eventItem); _domainEvents.Add(eventItem);
} }
public void RemoveEvent(IAsyncNotification eventItem) public void RemoveDomainEvent(IAsyncNotification eventItem)
{ {
if (_events is null) return; if (_domainEvents is null) return;
_events.Remove(eventItem); _domainEvents.Remove(eventItem);
} }
public bool IsTransient() public bool IsTransient()

View File

@ -10,9 +10,9 @@ namespace Ordering.Infrastructure
{ {
public static async Task RaiseDomainEventsAsync(this IMediator mediator, OrderingContext ctx) public static async Task RaiseDomainEventsAsync(this IMediator mediator, OrderingContext ctx)
{ {
var domainEntities = ctx.ChangeTracker.Entries<Entity>().Where(x => x.Entity.Events != null && x.Entity.Events.Any()); var domainEntities = ctx.ChangeTracker.Entries<Entity>().Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());
var domainEvents = domainEntities.SelectMany(x => x.Entity.Events).ToList(); var domainEvents = domainEntities.SelectMany(x => x.Entity.DomainEvents).ToList();
domainEntities.ToList().ForEach(entity => entity.Entity.Events.Clear()); domainEntities.ToList().ForEach(entity => entity.Entity.DomainEvents.Clear());
var tasks = domainEvents var tasks = domainEvents
.Select(async (domainEvent) => { .Select(async (domainEvent) => {

View File

@ -74,7 +74,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
buyerConfiguration.HasKey(b => b.Id); buyerConfiguration.HasKey(b => b.Id);
buyerConfiguration.Ignore(b => b.Events); buyerConfiguration.Ignore(b => b.DomainEvents);
buyerConfiguration.Property(b => b.Id) buyerConfiguration.Property(b => b.Id)
.ForSqlServerUseSequenceHiLo("buyerseq", DEFAULT_SCHEMA); .ForSqlServerUseSequenceHiLo("buyerseq", DEFAULT_SCHEMA);
@ -102,7 +102,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
paymentConfiguration.HasKey(b => b.Id); paymentConfiguration.HasKey(b => b.Id);
paymentConfiguration.Ignore(b => b.Events); paymentConfiguration.Ignore(b => b.DomainEvents);
paymentConfiguration.Property(b => b.Id) paymentConfiguration.Property(b => b.Id)
.ForSqlServerUseSequenceHiLo("paymentseq", DEFAULT_SCHEMA); .ForSqlServerUseSequenceHiLo("paymentseq", DEFAULT_SCHEMA);
@ -139,7 +139,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
orderConfiguration.HasKey(o => o.Id); orderConfiguration.HasKey(o => o.Id);
orderConfiguration.Ignore(b => b.Events); orderConfiguration.Ignore(b => b.DomainEvents);
orderConfiguration.Property(o => o.Id) orderConfiguration.Property(o => o.Id)
.ForSqlServerUseSequenceHiLo("orderseq", DEFAULT_SCHEMA); .ForSqlServerUseSequenceHiLo("orderseq", DEFAULT_SCHEMA);
@ -176,7 +176,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
orderItemConfiguration.HasKey(o => o.Id); orderItemConfiguration.HasKey(o => o.Id);
orderItemConfiguration.Ignore(b => b.Events); orderItemConfiguration.Ignore(b => b.DomainEvents);
orderItemConfiguration.Property(o => o.Id) orderItemConfiguration.Property(o => o.Id)
.ForSqlServerUseSequenceHiLo("orderitemseq"); .ForSqlServerUseSequenceHiLo("orderitemseq");
@ -238,6 +238,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
public async Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)) public async Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
{ {
var result = await base.SaveChangesAsync(); var result = await base.SaveChangesAsync();
// Dispatch the Domain Events collection right after saving/commiting data into the database
await _mediator.RaiseDomainEventsAsync(this); await _mediator.RaiseDomainEventsAsync(this);
return result; return result;
} }

View File

@ -122,6 +122,6 @@ public class BuyerAggregateTest
fakeBuyer.AddPaymentMethod(cardTypeId, alias, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration, orderId); fakeBuyer.AddPaymentMethod(cardTypeId, alias, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration, orderId);
//Assert //Assert
Assert.Equal(fakeBuyer.Events.Count, expectedResult); Assert.Equal(fakeBuyer.DomainEvents.Count, expectedResult);
} }
} }

View File

@ -112,7 +112,7 @@ public class OrderAggregateTest
var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
//Assert //Assert
Assert.Equal(fakeOrder.Events.Count, expectedResult); Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult);
} }
[Fact] [Fact]
@ -133,9 +133,9 @@ public class OrderAggregateTest
//Act //Act
var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
fakeOrder.AddEvent(new OrderCreated(fakeOrder,cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration)); fakeOrder.AddDomainEvent(new OrderCreatedDomainEvent(fakeOrder,cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration));
//Assert //Assert
Assert.Equal(fakeOrder.Events.Count, expectedResult); Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult);
} }
[Fact] [Fact]
@ -153,13 +153,13 @@ public class OrderAggregateTest
var cardHolderName = "FakeName"; var cardHolderName = "FakeName";
var cardExpiration = DateTime.Now.AddYears(1); var cardExpiration = DateTime.Now.AddYears(1);
var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var @fakeEvent = new OrderCreated(fakeOrder, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var @fakeEvent = new OrderCreatedDomainEvent(fakeOrder, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration);
var expectedResult = 1; var expectedResult = 1;
//Act //Act
fakeOrder.AddEvent(@fakeEvent); fakeOrder.AddDomainEvent(@fakeEvent);
fakeOrder.RemoveEvent(@fakeEvent); fakeOrder.RemoveDomainEvent(@fakeEvent);
//Assert //Assert
Assert.Equal(fakeOrder.Events.Count, expectedResult); Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult);
} }
} }