From d6ccf27100ff608877761ca1f738eae4f87c02d2 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Thu, 11 May 2017 18:39:06 +0200 Subject: [PATCH 01/10] OrderStockConfirmedDomainEvent implemented --- ...nOrderStockConfirmedDomainEventHandler.cs} | 31 +++++++++---------- ...tockNotConfirmedIntegrationEventHandler.cs | 12 ++++--- ...CheckoutAcceptedIntegrationEventHandler.cs | 1 - .../AggregatesModel/OrderAggregate/Order.cs | 11 ++++--- .../OrderStockMethodVerifiedDomainEvent.cs | 10 +++--- 5 files changed, 34 insertions(+), 31 deletions(-) rename src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/{UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs => OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs} (53%) diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs similarity index 53% rename from src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs rename to src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs index 40b2fa865..cd99f7d66 100644 --- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs @@ -1,4 +1,6 @@ -namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent +using System.Linq; + +namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent { using MediatR; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; @@ -9,14 +11,14 @@ using Ordering.API.Application.IntegrationCommands.Commands; using Ordering.API.Application.IntegrationEvents; - public class UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler - : IAsyncNotificationHandler + public class OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler + : IAsyncNotificationHandler { private readonly IOrderRepository _orderRepository; private readonly ILoggerFactory _logger; private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; - public UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler( + public OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler( IOrderRepository orderRepository, ILoggerFactory logger, IOrderingIntegrationEventService orderingIntegrationEventService) { @@ -25,23 +27,18 @@ _orderingIntegrationEventService = orderingIntegrationEventService; } - public async Task Handle(OrderStockMethodVerifiedDomainEvent orderStockMethodVerifiedDomainEvent) + public async Task Handle(OrderStockConfirmedDomainEvent orderStockMethodVerifiedDomainEvent) { - var orderToUpdate = await _orderRepository.GetAsync(orderStockMethodVerifiedDomainEvent.OrderId); - orderToUpdate.SetOrderStatusId(orderStockMethodVerifiedDomainEvent.OrderStatus.Id); - - _orderRepository.Update(orderToUpdate); - - await _orderRepository.UnitOfWork - .SaveEntitiesAsync(); - - _logger.CreateLogger(nameof(UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler)) + _logger.CreateLogger(nameof(OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler)) .LogTrace($"Order with Id: {orderStockMethodVerifiedDomainEvent.OrderId} has been successfully updated with " + $"a status order id: { orderStockMethodVerifiedDomainEvent.OrderStatus.Id }"); - var payOrderCommandMsg = new PayOrderCommandMsg(orderToUpdate.Id); - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); - await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); + if (orderStockMethodVerifiedDomainEvent.OrderStatus == OrderStatus.StockValidated) + { + var payOrderCommandMsg = new PayOrderCommandMsg(orderStockMethodVerifiedDomainEvent.OrderId); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); + } } } } \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs index dfcb1d480..04c9babb0 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -1,4 +1,5 @@ using System.Linq; +using Ordering.API.Application.IntegrationCommands.Commands; namespace Ordering.API.Application.IntegrationEvents.EventHandling { @@ -25,15 +26,18 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling public async Task Handle(OrderStockNotConfirmedIntegrationEvent @event) { - //TODO: must update the order state to cancelled and the CurrentOrderStateContextDescription with the reasons of no-stock confirm - var order = await _orderRepository.GetAsync(@event.OrderId); - CheckValidSagaId(order); + var orderToUpdate = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(orderToUpdate); var orderStockNotConfirmedItems = @event.OrderStockItems .FindAll(c => !c.Confirmed) .Select(c => c.ProductId); - order.SetOrderStockConfirmed(orderStockNotConfirmedItems); + orderToUpdate.SetOrderStockConfirmed(orderStockNotConfirmedItems); + + var payOrderCommandMsg = new PayOrderCommandMsg(orderToUpdate.Id); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); } private void CheckValidSagaId(Order orderSaga) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs index f28544a6f..ab325fa03 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs @@ -14,7 +14,6 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling private readonly ILoggerFactory _logger; public UserCheckoutAcceptedIntegrationEventHandler(IMediator mediator, - IOrderingIntegrationEventService orderingIntegrationEventService, ILoggerFactory logger) { _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator)); diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index 1920eb030..c1e2c4184 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -103,21 +103,22 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O if(orderStockNotConfirmedItems is null) { OrderStatus = OrderStatus.StockValidated; + _description = "All the items were confirmed with available stock."; - //AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.StockValidated)); } else { + OrderStatus = OrderStatus.Cancelled; + var itemsStockNotConfirmedProductNames = OrderItems .Where(c => orderStockNotConfirmedItems.Contains(c.ProductId)) .Select(c => c.GetOrderItemProductName()); var itemsStockNotConfirmedDescription = string.Join(", ", itemsStockNotConfirmedProductNames); - - OrderStatus = OrderStatus.Cancelled; - _description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription})."; - //AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.Cancelled)); + _description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription})."; } + + AddDomainEvent(new OrderStockConfirmedDomainEvent(Id, OrderStatus)); } private void AddOrderStartedDomainEvent(int cardTypeId, string cardNumber, diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs index c5acd26dd..86f9c34d4 100644 --- a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs @@ -1,18 +1,20 @@ -namespace Ordering.Domain.Events +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + +namespace Ordering.Domain.Events { using MediatR; - using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using System.Collections.Generic; /// /// Event used when the order stock items are verified /// - public class OrderStockMethodVerifiedDomainEvent + public class OrderStockConfirmedDomainEvent : IAsyncNotification { public int OrderId { get; } public OrderStatus OrderStatus { get; } - public OrderStockMethodVerifiedDomainEvent(int orderId, + public OrderStockConfirmedDomainEvent(int orderId, OrderStatus orderStatus) { OrderId = orderId; From 04c9579bcb1a050d574212bd9577ca5911cb9241 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Thu, 11 May 2017 18:41:34 +0200 Subject: [PATCH 02/10] Remove old integration event call from OrderStockConfirmedIntegrationEventHandler --- .../OrderStockConfirmedIntegrationEventHandler.cs | 10 ---------- .../OrderStockNotConfirmedIntegrationEventHandler.cs | 4 ---- 2 files changed, 14 deletions(-) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index cfc2fdbe0..a78a4dda8 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -22,20 +22,10 @@ public async Task Handle(OrderStockConfirmedIntegrationEvent @event) { - //TODO: 1) Updates the state to "StockValidated" and any meaningful OrderContextDescription message saying that all the items were confirmed with available stock, etc var order = await _orderRepository.GetAsync(@event.OrderId); CheckValidSagaId(order); order.SetOrderStockConfirmed(); - - //Create Integration Event to be published through the Event Bus - var payOrderCommandMsg = new PayOrderCommandMsg(order.Id); - - // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); - - // Publish through the Event Bus and mark the saved event as published - await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); } private void CheckValidSagaId(Order orderSaga) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs index 04c9babb0..6c210b5af 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -34,10 +34,6 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling .Select(c => c.ProductId); orderToUpdate.SetOrderStockConfirmed(orderStockNotConfirmedItems); - - var payOrderCommandMsg = new PayOrderCommandMsg(orderToUpdate.Id); - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); - await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); } private void CheckValidSagaId(Order orderSaga) From 11dde7031603566d267b1a840014027cb850d731 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Thu, 11 May 2017 18:43:13 +0200 Subject: [PATCH 03/10] remove unused Interfaces dependencies --- .../OrderStockConfirmedIntegrationEventHandler.cs | 5 +---- .../OrderStockNotConfirmedIntegrationEventHandler.cs | 9 ++------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index a78a4dda8..4336e9326 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -10,14 +10,11 @@ public class OrderStockConfirmedIntegrationEventHandler : IIntegrationEventHandler { - private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderRepository _orderRepository; - public OrderStockConfirmedIntegrationEventHandler(IOrderRepository orderRepository, - IOrderingIntegrationEventService orderingIntegrationEventService) + public OrderStockConfirmedIntegrationEventHandler(IOrderRepository orderRepository) { _orderRepository = orderRepository; - _orderingIntegrationEventService = orderingIntegrationEventService; } public async Task Handle(OrderStockConfirmedIntegrationEvent @event) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs index 6c210b5af..a60e59f89 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -8,20 +8,15 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling using System.Threading.Tasks; using Events; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; - using Ordering.API.Application.Sagas; - using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; - using Ordering.Domain.Exceptions; + using Domain.Exceptions; public class OrderStockNotConfirmedIntegrationEventHandler : IIntegrationEventHandler { - private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderRepository _orderRepository; - public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository, - IOrderingIntegrationEventService orderingIntegrationEventService) + public OrderStockNotConfirmedIntegrationEventHandler(IOrderRepository orderRepository) { _orderRepository = orderRepository; - _orderingIntegrationEventService = orderingIntegrationEventService; } public async Task Handle(OrderStockNotConfirmedIntegrationEvent @event) From 1cdb541f305580f14d868600c3b95d67240366ab Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 10:13:26 +0200 Subject: [PATCH 04/10] Fix some test changes --- .../Application/IdentifierCommandHandlerTest.cs | 1 + .../Application/NewOrderCommandHandlerTest.cs | 3 ++- .../Ordering/Domain/OrderAggregateTest.cs | 17 ++++++++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs b/test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs index d9cc878a5..b2f2f6a5d 100644 --- a/test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs +++ b/test/Services/UnitTest/Ordering/Application/IdentifierCommandHandlerTest.cs @@ -71,6 +71,7 @@ namespace UnitTest.Ordering.Application { return new CreateOrderCommand( null, + userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null, city: args != null && args.ContainsKey("city") ? (string)args["city"] : null, street: args != null && args.ContainsKey("street") ? (string)args["street"] : null, state: args != null && args.ContainsKey("state") ? (string)args["state"] : null, diff --git a/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs b/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs index 2979fa561..98f5292ef 100644 --- a/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs +++ b/test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs @@ -66,13 +66,14 @@ namespace UnitTest.Ordering.Application private Order FakeOrder() { - return new Order(new Address("street", "city", "state", "country", "zipcode"), 1, "12", "111", "fakeName", DateTime.Now.AddYears(1)); + return new Order(new Guid().ToString(), new Address("street", "city", "state", "country", "zipcode"), 1, "12", "111", "fakeName", DateTime.Now.AddYears(1)); } private CreateOrderCommand FakeOrderRequestWithBuyer(Dictionary args = null) { return new CreateOrderCommand( null, + userId: args != null && args.ContainsKey("userId") ? (string)args["userId"] : null, city: args != null && args.ContainsKey("city") ? (string)args["city"] : null, street: args != null && args.ContainsKey("street") ? (string)args["street"] : null, state: args != null && args.ContainsKey("state") ? (string)args["state"] : null, diff --git a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs index 40bc66431..28ee18078 100644 --- a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs +++ b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs @@ -96,7 +96,8 @@ public class OrderAggregateTest [Fact] public void Add_new_Order_raises_new_event() { - //Arrange + //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState"; @@ -110,7 +111,7 @@ public class OrderAggregateTest var expectedResult = 1; //Act - var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); + var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); //Assert Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); @@ -119,7 +120,8 @@ public class OrderAggregateTest [Fact] public void Add_event_Order_explicitly_raises_new_event() { - //Arrange + //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState"; @@ -133,8 +135,8 @@ public class OrderAggregateTest var expectedResult = 2; //Act - var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); - fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder,cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration)); + var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); + fakeOrder.AddDomainEvent(new OrderStartedDomainEvent(fakeOrder, userId.ToString(), cardTypeId,cardNumber,cardSecurityNumber,cardHolderName,cardExpiration)); //Assert Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); } @@ -143,6 +145,7 @@ public class OrderAggregateTest public void Remove_event_Order_explicitly() { //Arrange + var userId = new Guid(); var street = "fakeStreet"; var city = "FakeCity"; var state = "fakeState"; @@ -153,8 +156,8 @@ public class OrderAggregateTest var cardSecurityNumber = "123"; var cardHolderName = "FakeName"; var cardExpiration = DateTime.Now.AddYears(1); - var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); - var @fakeEvent = new OrderStartedDomainEvent(fakeOrder, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); + var fakeOrder = new Order(userId.ToString(), new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); + var @fakeEvent = new OrderStartedDomainEvent(fakeOrder, userId.ToString(), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var expectedResult = 1; //Act From 830d0597d76f0c555f419bcf06c3f6646f99bc92 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:05:47 +0200 Subject: [PATCH 05/10] Add OrderStockConfirmed and ProductPriceChanged IntegrationEvent --- .../ConfirmOrderStockCommandMsgHandler.cs} | 15 +++---- .../DecrementOrderStockCommandMsgHandler.cs | 42 +++++++++++++++++++ .../Commands/ConfirmOrderStockCommandMsg.cs} | 6 +-- .../Commands/DecrementOrderStockCommandMsg.cs | 18 ++++++++ .../OrderStockConfirmedIntegrationEvent.cs | 2 +- .../ProductPriceChangedIntegrationEvent.cs | 11 ++--- src/Services/Catalog/Catalog.API/Startup.cs | 17 +++++++- 7 files changed, 90 insertions(+), 21 deletions(-) rename src/Services/Catalog/Catalog.API/{IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs => IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs} (77%) create mode 100644 src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs rename src/Services/Catalog/Catalog.API/{IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs => IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs} (81%) create mode 100644 src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs similarity index 77% rename from src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs rename to src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs index 21d12e1ee..beb23bbaf 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/EventHandling/ConfirmOrderStockIntegrationEventHandler.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/ConfirmOrderStockCommandMsgHandler.cs @@ -1,4 +1,4 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers { using BuildingBlocks.EventBus.Abstractions; using System.Threading.Tasks; @@ -9,21 +9,22 @@ using global::Catalog.API.Infrastructure.Exceptions; using global::Catalog.API.IntegrationEvents; using Model; - using Events; + using Commands; + using IntegrationEvents.Events; - public class ConfirmOrderStockIntegrationEventHandler : IIntegrationEventHandler + public class ConfirmOrderStockCommandMsgHandler : IIntegrationEventHandler { private readonly CatalogContext _catalogContext; private readonly ICatalogIntegrationEventService _catalogIntegrationEventService; - public ConfirmOrderStockIntegrationEventHandler(CatalogContext catalogContext, + public ConfirmOrderStockCommandMsgHandler(CatalogContext catalogContext, ICatalogIntegrationEventService catalogIntegrationEventService) { _catalogContext = catalogContext; _catalogIntegrationEventService = catalogIntegrationEventService; } - public async Task Handle(ConfirmOrderStockIntegrationEvent @event) + public async Task Handle(ConfirmOrderStockCommandMsg @event) { var confirmedOrderStockItems = new List(); @@ -38,15 +39,11 @@ confirmedOrderStockItems.Add(confirmedOrderStockItem); } - //Create Integration Event to be published through the Event Bus var confirmedIntegrationEvent = confirmedOrderStockItems.Any(c => !c.Confirmed) ? (IntegrationEvent) new OrderStockNotConfirmedIntegrationEvent(@event.OrderId, confirmedOrderStockItems) : new OrderStockConfirmedIntegrationEvent(@event.OrderId); - // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(confirmedIntegrationEvent); - - // Publish through the Event Bus and mark the saved event as published await _catalogIntegrationEventService.PublishThroughEventBusAsync(confirmedIntegrationEvent); } diff --git a/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs new file mode 100644 index 000000000..962f5222d --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/CommandHandlers/DecrementOrderStockCommandMsgHandler.cs @@ -0,0 +1,42 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers +{ + using BuildingBlocks.EventBus.Abstractions; + using System.Threading.Tasks; + using Infrastructure; + using global::Catalog.API.Infrastructure.Exceptions; + using global::Catalog.API.IntegrationEvents; + using Model; + using Commands; + + public class DecrementOrderStockCommandMsgHandler : IIntegrationEventHandler + { + private readonly CatalogContext _catalogContext; + + public DecrementOrderStockCommandMsgHandler(CatalogContext catalogContext) + { + _catalogContext = catalogContext; + } + + public async Task Handle(DecrementOrderStockCommandMsg @event) + { + //we're not blocking stock/inventory + foreach (var orderStockItem in @event.OrderStockItems) + { + var catalogItem = _catalogContext.CatalogItems.Find(orderStockItem.ProductId); + CheckValidcatalogItemId(catalogItem); + + catalogItem.RemoveStock(orderStockItem.Units); + } + + await _catalogContext.SaveChangesAsync(); + } + + private void CheckValidcatalogItemId(CatalogItem catalogItem) + { + if (catalogItem is null) + { + throw new CatalogDomainException("Not able to process catalog event. Reason: no valid catalogItemId"); + } + } + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs similarity index 81% rename from src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs rename to src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs index 366c8f854..f5fc805b2 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ConfirmOrderStockIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs @@ -1,14 +1,14 @@ -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands { using BuildingBlocks.EventBus.Events; using System.Collections.Generic; - public class ConfirmOrderStockIntegrationEvent : IntegrationEvent + public class ConfirmOrderStockCommandMsg : IntegrationEvent { public int OrderId { get; } public IEnumerable OrderStockItems { get; } - public ConfirmOrderStockIntegrationEvent(int orderId, + public ConfirmOrderStockCommandMsg(int orderId, IEnumerable orderStockItems) { OrderId = orderId; diff --git a/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs new file mode 100644 index 000000000..94bab1aa6 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs @@ -0,0 +1,18 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands +{ + using System.Collections.Generic; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class DecrementOrderStockCommandMsg : IntegrationEvent + { + public int OrderId { get; } + public IEnumerable OrderStockItems { get; } + + public DecrementOrderStockCommandMsg(int orderId, + IEnumerable orderStockItems) + { + OrderId = orderId; + OrderStockItems = orderStockItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs index 1ce179c3a..b91eaae43 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/OrderStockConfirmedIntegrationEvent.cs @@ -1,6 +1,6 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events { - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using BuildingBlocks.EventBus.Events; public class OrderStockConfirmedIntegrationEvent : IntegrationEvent { diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs index 10b8317da..7c14a07d1 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs @@ -1,10 +1,7 @@ -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events { + using BuildingBlocks.EventBus.Events; + // Integration Events notes: // An Event is “something that has happened in the past”, therefore its name has to be // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. @@ -23,4 +20,4 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Eve OldPrice = oldPrice; } } -} +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index 509048d4c..e224dea0a 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -14,6 +14,9 @@ using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandsHandlers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; @@ -24,7 +27,7 @@ using System.Data.Common; using System.Data.SqlClient; using System.Reflection; - + public class Startup { public IConfigurationRoot Configuration { get; } @@ -120,6 +123,8 @@ services.AddSingleton(); services.AddSingleton(); + services.AddTransient, ConfirmOrderStockCommandMsgHandler>(); + services.AddTransient, DecrementOrderStockCommandMsgHandler>(); var container = new ContainerBuilder(); container.Populate(services); @@ -149,6 +154,8 @@ CatalogContextSeed.SeedAsync(app, loggerFactory) .Wait(); + ConfigureEventBus(app); + var integrationEventLogContext = new IntegrationEventLogContext( new DbContextOptionsBuilder() .UseSqlServer(Configuration["ConnectionString"], b => b.MigrationsAssembly("Catalog.API")) @@ -180,5 +187,13 @@ ctx.Database.CloseConnection(); } } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + + eventBus.Subscribe>(); + eventBus.Subscribe>(); + } } } From 82fe8595848c7ebc595a9eef5e15c48ee5fa3d12 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:14:37 +0200 Subject: [PATCH 06/10] Adding Integration Event handlers to ordering Api --- .../Commands/CreateOrderCommand.cs | 2 +- .../Commands/CreateOrderCommandHandler.cs | 2 +- ...dToAwaitingValidationDomainEventHandler.cs | 46 +++++++++++++++++ ...erStatusChangedToPaidDomainEventHandler.cs | 51 +++++++++++++++++++ ...enOrderStockConfirmedDomainEventHandler.cs | 44 ---------------- ...angedToStockConfirmedDomainEventHandler.cs | 41 +++++++++++++++ .../Commands/ConfirmOrderStockCommandMsg.cs | 6 +-- .../Commands/DecrementOrderStockCommandMsg.cs | 18 +++++++ .../Commands/ShipOrderCommandMsg.cs | 14 +++++ ...derPaymentFailedIntegrationEventHandler.cs | 9 ++++ ...rPaymentSuccededIntegrationEventHandler.cs | 23 ++++++++- ...erStockConfirmedIntegrationEventHandler.cs | 2 +- ...tockNotConfirmedIntegrationEventHandler.cs | 2 +- .../Application/Sagas/OrderProcessSaga.cs | 18 ++----- .../Application/Sagas/OrderSaga.cs | 36 +++++++++++++ .../Ordering.API/Application/Sagas/Saga.cs | 18 +++---- .../Infrastructure/OrderingContextSeed.cs | 2 +- src/Services/Ordering/Ordering.API/Startup.cs | 4 +- 18 files changed, 256 insertions(+), 82 deletions(-) create mode 100644 src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs delete mode 100644 src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs create mode 100644 src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs index 19fa3b818..fc6fd97d0 100644 --- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs +++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs @@ -88,7 +88,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands var result = new List(); basketItems.ForEach((item) => { result.Add(new OrderItemDTO() { - ProductId = int.TryParse(item.Id, out int id) ? id : -1, + ProductId = int.TryParse(item.ProductId, out int id) ? id : -1, ProductName = item.ProductName, PictureUrl = item.PictureUrl, UnitPrice = item.UnitPrice, diff --git a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs index c0d0a0d2b..3ef80a69a 100644 --- a/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs @@ -43,7 +43,7 @@ // make sure that consistency is preserved across the whole aggregate var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode); var order = new Order(message.UserId, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration); - order.SetOrderStatusId(OrderStatus.Submited.Id); + order.SetSubmitedStatus(); foreach (var item in message.OrderItems) { order.AddOrderItem(item.ProductId, item.ProductName, item.UnitPrice, item.Discount, item.PictureUrl, item.Units); diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs new file mode 100644 index 000000000..d6906705f --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs @@ -0,0 +1,46 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderGracePeriodConfirmed +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents; + using System.Linq; + + public class OrderStatusChangedToAwaitingValidationDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + + public OrderStatusChangedToAwaitingValidationDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _orderingIntegrationEventService = orderingIntegrationEventService; + } + + public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent) + { + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(OrderStatusChangedToAwaitingValidationDomainEvent)) + .LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.AwaitingValidation.Id}"); + + var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems + .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + + var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderStatusChangedToAwaitingValidationDomainEvent.OrderId, + orderStockList); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockEvent); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs new file mode 100644 index 000000000..1eb4a8953 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs @@ -0,0 +1,51 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderPaid +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents; + using System.Linq; + + public class OrderStatusChangedToPaidDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + + public OrderStatusChangedToPaidDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _orderingIntegrationEventService = orderingIntegrationEventService; + } + + public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent) + { + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(OrderStatusChangedToPaidDomainEventHandler)) + .LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.Paid.Id}"); + + var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems + .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); + + var decrementOrderStockCommandMsg = new DecrementOrderStockCommandMsg(orderStatusChangedToPaidDomainEvent.OrderId, + orderStockList); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(decrementOrderStockCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(decrementOrderStockCommandMsg); + + //is it necessary get a DecrementOrderStockSuccessIntegrationEvent/DecrementOrderStockFailedIntegrationEvent before to call ShipOrderCommandMsg??? + var shipOrderCommandMsg = new ShipOrderCommandMsg(orderStatusChangedToPaidDomainEvent.OrderId); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(shipOrderCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(shipOrderCommandMsg); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs deleted file mode 100644 index cd99f7d66..000000000 --- a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmation/OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Linq; - -namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent -{ - using MediatR; - using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; - using Microsoft.Extensions.Logging; - using Domain.Events; - using System; - using System.Threading.Tasks; - using Ordering.API.Application.IntegrationCommands.Commands; - using Ordering.API.Application.IntegrationEvents; - - public class OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler - : IAsyncNotificationHandler - { - private readonly IOrderRepository _orderRepository; - private readonly ILoggerFactory _logger; - private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; - - public OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler( - IOrderRepository orderRepository, ILoggerFactory logger, - IOrderingIntegrationEventService orderingIntegrationEventService) - { - _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _orderingIntegrationEventService = orderingIntegrationEventService; - } - - public async Task Handle(OrderStockConfirmedDomainEvent orderStockMethodVerifiedDomainEvent) - { - _logger.CreateLogger(nameof(OrderStatusChangedWhenOrderStockConfirmedDomainEventHandler)) - .LogTrace($"Order with Id: {orderStockMethodVerifiedDomainEvent.OrderId} has been successfully updated with " + - $"a status order id: { orderStockMethodVerifiedDomainEvent.OrderStatus.Id }"); - - if (orderStockMethodVerifiedDomainEvent.OrderStatus == OrderStatus.StockValidated) - { - var payOrderCommandMsg = new PayOrderCommandMsg(orderStockMethodVerifiedDomainEvent.OrderId); - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); - await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); - } - } - } -} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs new file mode 100644 index 000000000..2de4f5095 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs @@ -0,0 +1,41 @@ +namespace Ordering.API.Application.DomainEventHandlers.OrderStockConfirmed +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using Microsoft.Extensions.Logging; + using Domain.Events; + using System; + using System.Threading.Tasks; + using Ordering.API.Application.IntegrationCommands.Commands; + using Ordering.API.Application.IntegrationEvents; + + public class OrderStatusChangedToStockConfirmedDomainEventHandler + : IAsyncNotificationHandler + { + private readonly IOrderRepository _orderRepository; + private readonly ILoggerFactory _logger; + private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; + + public OrderStatusChangedToStockConfirmedDomainEventHandler( + IOrderRepository orderRepository, ILoggerFactory logger, + IOrderingIntegrationEventService orderingIntegrationEventService) + { + _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _orderingIntegrationEventService = orderingIntegrationEventService; + } + + public async Task Handle(OrderStatusChangedToStockConfirmedDomainEvent orderStatusChangedToStockConfirmedDomainEvent) + { + await _orderRepository.UnitOfWork.SaveEntitiesAsync(); + + _logger.CreateLogger(nameof(OrderStatusChangedToStockConfirmedDomainEventHandler)) + .LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " + + $"a status order id: {OrderStatus.StockConfirmed.Id}"); + + var payOrderCommandMsg = new PayOrderCommandMsg(orderStatusChangedToStockConfirmedDomainEvent.OrderId); + await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg); + await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg); + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs index abf93d0ef..6e78598f1 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ConfirmOrderStockCommandMsg.cs @@ -6,13 +6,13 @@ public class ConfirmOrderStockCommandMsg : IntegrationEvent { public int OrderId { get; } - public IEnumerable OrderStockItem { get; } + public IEnumerable OrderStockItems { get; } public ConfirmOrderStockCommandMsg(int orderId, - IEnumerable orderStockItem) + IEnumerable orderStockItems) { OrderId = orderId; - OrderStockItem = orderStockItem; + OrderStockItems = orderStockItems; } } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs new file mode 100644 index 000000000..e05a20c48 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/DecrementOrderStockCommandMsg.cs @@ -0,0 +1,18 @@ +namespace Ordering.API.Application.IntegrationCommands.Commands +{ + using System.Collections.Generic; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class DecrementOrderStockCommandMsg : IntegrationEvent + { + public int OrderId { get; } + public IEnumerable OrderStockItems { get; } + + public DecrementOrderStockCommandMsg(int orderId, + IEnumerable orderStockItems) + { + OrderId = orderId; + OrderStockItems = orderStockItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs new file mode 100644 index 000000000..5a8695ae9 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationCommands/Commands/ShipOrderCommandMsg.cs @@ -0,0 +1,14 @@ +namespace Ordering.API.Application.IntegrationCommands.Commands +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class ShipOrderCommandMsg : IntegrationEvent + { + public int OrderId { get; } + + public ShipOrderCommandMsg(int orderId) + { + OrderId = orderId; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs index 485cf750f..074b2799b 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentFailedIntegrationEventHandler.cs @@ -1,14 +1,23 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Ordering.API.Application.IntegrationEvents.Events; using System.Threading.Tasks; public class OrderPaymentFailedIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderRepository _orderRepository; + + public OrderPaymentFailedIntegrationEventHandler(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + public async Task Handle(OrderPaymentFailedIntegrationEvent @event) { + //TODO: Cancel Order } } } diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs index 86e3d5482..98ba54b08 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderPaymentSuccededIntegrationEventHandler.cs @@ -1,14 +1,35 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling { using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; using Ordering.API.Application.IntegrationEvents.Events; + using Ordering.Domain.Exceptions; using System.Threading.Tasks; public class OrderPaymentSuccededIntegrationEventHandler : IIntegrationEventHandler { + private readonly IOrderRepository _orderRepository; + + public OrderPaymentSuccededIntegrationEventHandler(IOrderRepository orderRepository) + { + _orderRepository = orderRepository; + } + public async Task Handle(OrderPaymentSuccededIntegrationEvent @event) { + var order = await _orderRepository.GetAsync(@event.OrderId); + CheckValidSagaId(order); + + order.SetPaidStatus(); + } + + private void CheckValidSagaId(Order orderSaga) + { + if (orderSaga is null) + { + throw new OrderingDomainException("Not able to process order saga event. Reason: no valid orderId"); + } } } -} +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs index 4336e9326..98d4fda08 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockConfirmedIntegrationEventHandler.cs @@ -22,7 +22,7 @@ var order = await _orderRepository.GetAsync(@event.OrderId); CheckValidSagaId(order); - order.SetOrderStockConfirmed(); + order.SetStockConfirmedStatus(); } private void CheckValidSagaId(Order orderSaga) diff --git a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs index a60e59f89..d80a966f0 100644 --- a/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/OrderStockNotConfirmedIntegrationEventHandler.cs @@ -28,7 +28,7 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling .FindAll(c => !c.Confirmed) .Select(c => c.ProductId); - orderToUpdate.SetOrderStockConfirmed(orderStockNotConfirmedItems); + orderToUpdate.SetStockConfirmedStatus(orderStockNotConfirmedItems); } private void CheckValidSagaId(Order orderSaga) diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs index 8a4c51795..9ebeb21b7 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderProcessSaga.cs @@ -7,15 +7,11 @@ using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency; using Ordering.API.Application.Commands; using Ordering.API.Application.IntegrationCommands.Commands; -using Ordering.API.Application.IntegrationEvents.Events; using Ordering.Domain.Exceptions; using System; -using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Threading.Tasks; using Ordering.API.Application.IntegrationEvents; -using Ordering.API.Application.IntegrationEvents.Events; namespace Ordering.API.Application.Sagas { @@ -27,7 +23,7 @@ namespace Ordering.API.Application.Sagas /// the opportunity to cancel the order before proceeding /// with the validations. /// - public class OrderProcessSaga : Saga, + public class OrderProcessSaga : OrderSaga, IIntegrationEventHandler, IAsyncRequestHandler { @@ -63,17 +59,9 @@ namespace Ordering.API.Application.Sagas if (orderSaga.OrderStatus != OrderStatus.Cancelled) { - orderSaga.SetOrderStatusId(OrderStatus.AwaitingValidation.Id); - await SaveChangesAsync(); - - var orderStockList = orderSaga.OrderItems - .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); - - var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList); + orderSaga.SetAwaitingValidationStatus(); - await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockEvent); - - await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent); + await SaveChangesAsync(); } } diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs new file mode 100644 index 000000000..dd8e46ac7 --- /dev/null +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/OrderSaga.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; +using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure; + +namespace Ordering.API.Application.Sagas +{ + public abstract class OrderSaga : Saga + { + private OrderingContext _orderingContext; + + public OrderSaga(OrderingContext orderingContext) : base(orderingContext) + { + _orderingContext = orderingContext; + } + + public override Order FindSagaById(int id) + { + var order = _orderingContext.Orders + .Single(c => c.Id == id); + + _orderingContext.Entry(order) + .Member("OrderStatus"); + + return order; + } + + public override async Task SaveChangesAsync() + { + return await _orderingContext.SaveEntitiesAsync(); + } + } +} diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs index 14925f93f..caaa3fa37 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs @@ -14,17 +14,13 @@ namespace Ordering.API.Application.Sagas _dbContext = dbContext; } - protected TEntity FindSagaById(int id, DbContext context = null) - { - var ctx = context ?? _dbContext; - return ctx.Set().Where(x => x.Id == id).SingleOrDefault(); - } + public abstract TEntity FindSagaById(int id); - protected async Task SaveChangesAsync(DbContext context = null) - { - var ctx = context ?? _dbContext; - var result = await ctx.SaveChangesAsync(); - return result > 0; - } + public abstract Task SaveChangesAsync(); + //{ + // var ctx = context ?? _dbContext; + // var result = await ctx.SaveChangesAsync(); + // return result > 0; + //} } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs index b41d019fb..68b1baf34 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/OrderingContextSeed.cs @@ -33,7 +33,7 @@ { context.OrderStatus.Add(OrderStatus.Submited); context.OrderStatus.Add(OrderStatus.AwaitingValidation); - context.OrderStatus.Add(OrderStatus.StockValidated); + context.OrderStatus.Add(OrderStatus.StockConfirmed); context.OrderStatus.Add(OrderStatus.Paid); context.OrderStatus.Add(OrderStatus.Shipped); context.OrderStatus.Add(OrderStatus.Cancelled); diff --git a/src/Services/Ordering/Ordering.API/Startup.cs b/src/Services/Ordering/Ordering.API/Startup.cs index b5b01e068..4f3ca9dfa 100644 --- a/src/Services/Ordering/Ordering.API/Startup.cs +++ b/src/Services/Ordering/Ordering.API/Startup.cs @@ -7,7 +7,6 @@ using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Infrastructure.Middlewares; using global::Ordering.API.Application.IntegrationCommands.Commands; - using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Application.Sagas; using Infrastructure; using Infrastructure.Auth; @@ -31,7 +30,6 @@ using System; using System.Data.Common; using System.Reflection; - using global::Ordering.API.Application.IntegrationEvents.EventHandling; public class Startup { @@ -110,7 +108,7 @@ services.AddTransient(); services.AddTransient>( sp => (DbConnection c) => new IntegrationEventLogService(c)); - var serviceProvider = services.BuildServiceProvider(); + services.AddTransient(); services.AddSingleton(sp => From 2ade7a87e8ba2a3455175855bb7d571533d071c8 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:15:33 +0200 Subject: [PATCH 07/10] Add Integration Events and Pay Order Command msg handler --- docker-compose.vs.debug.yml | 2 +- docker-compose.yml | 2 +- .../PayOrderCommandMsgHandler.cs | 19 ++++++++++++ .../Commands/PayOrderCommandMsg.cs | 11 +++++++ .../OrderPaymentFailedIntegrationEvent.cs | 11 +++++++ .../OrderPaymentSuccededIntegrationEvent.cs | 11 +++++++ .../Payment/Payment.API/Payment.API.csproj | 5 ++++ src/Services/Payment/Payment.API/Startup.cs | 30 +++++++++++++++++++ 8 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs create mode 100644 src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs create mode 100644 src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs create mode 100644 src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs diff --git a/docker-compose.vs.debug.yml b/docker-compose.vs.debug.yml index eaa0b6f35..f6187dee2 100644 --- a/docker-compose.vs.debug.yml +++ b/docker-compose.vs.debug.yml @@ -107,7 +107,7 @@ services: - "com.microsoft.visualstudio.targetoperatingsystem=linux" payment.api: - image: payment.api:dev + image: eshop/payment.api:dev build: args: source: ${DOCKER_BUILD_SOURCE} diff --git a/docker-compose.yml b/docker-compose.yml index cc134a005..75177c5db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,7 +86,7 @@ services: dockerfile: Dockerfile payment.api: - image: payment.api + image: eshop/payment.api build: context: ./src/Services/Payment/Payment.API dockerfile: Dockerfile diff --git a/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs b/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs new file mode 100644 index 000000000..0a41c133c --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationCommands/CommandHandlers/PayOrderCommandMsgHandler.cs @@ -0,0 +1,19 @@ +namespace Payment.API.IntegrationCommands.CommandHandlers +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Payment.API.IntegrationCommands.Commands; + using System.Threading.Tasks; + using System; + + public class PayOrderCommandMsgHandler : IIntegrationEventHandler + { + public PayOrderCommandMsgHandler() + { + } + + public async Task Handle(PayOrderCommandMsg @event) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs b/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs new file mode 100644 index 000000000..360f40606 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationCommands/Commands/PayOrderCommandMsg.cs @@ -0,0 +1,11 @@ +namespace Payment.API.IntegrationCommands.Commands +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class PayOrderCommandMsg : IntegrationEvent + { + public int OrderId { get; } + + public PayOrderCommandMsg(int orderId) => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs new file mode 100644 index 000000000..d51c518c4 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentFailedIntegrationEvent.cs @@ -0,0 +1,11 @@ +namespace Payment.API.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class OrderPaymentFailedIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public OrderPaymentFailedIntegrationEvent(int orderId) => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs new file mode 100644 index 000000000..d672ff9d4 --- /dev/null +++ b/src/Services/Payment/Payment.API/IntegrationEvents/Events/OrderPaymentSuccededIntegrationEvent.cs @@ -0,0 +1,11 @@ +namespace Payment.API.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + + public class OrderPaymentSuccededIntegrationEvent : IntegrationEvent + { + public int OrderId { get; } + + public OrderPaymentSuccededIntegrationEvent(int orderId) => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Payment/Payment.API/Payment.API.csproj b/src/Services/Payment/Payment.API/Payment.API.csproj index 147cd2e3c..7f741fa53 100644 --- a/src/Services/Payment/Payment.API/Payment.API.csproj +++ b/src/Services/Payment/Payment.API/Payment.API.csproj @@ -25,5 +25,10 @@ + + + + + diff --git a/src/Services/Payment/Payment.API/Startup.cs b/src/Services/Payment/Payment.API/Startup.cs index c5160a81d..ac970d82d 100644 --- a/src/Services/Payment/Payment.API/Startup.cs +++ b/src/Services/Payment/Payment.API/Startup.cs @@ -6,6 +6,11 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Payment.API.IntegrationCommands.Commands; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; +using RabbitMQ.Client; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; namespace Payment.API { @@ -29,6 +34,21 @@ namespace Payment.API // Add framework services. services.AddMvc(); + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = Configuration["EventBusConnection"] + }; + + return new DefaultRabbitMQPersistentConnection(factory, logger); + }); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSwaggerGen(); services.ConfigureSwaggerGen(options => { @@ -47,6 +67,8 @@ namespace Payment.API return new AutofacServiceProvider(container.Build()); } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { @@ -57,6 +79,14 @@ namespace Payment.API app.UseSwagger() .UseSwaggerUi(); + + ConfigureEventBus(app); + } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe>(); } } } From f65ce1b9ee2d13c69e77b2aa45c0b0b7d2bee413 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:16:15 +0200 Subject: [PATCH 08/10] Change to Task.Delay --- src/Services/SagaManager/SagaManager/Program.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Services/SagaManager/SagaManager/Program.cs b/src/Services/SagaManager/SagaManager/Program.cs index 0e5e1dc5a..95105b23b 100644 --- a/src/Services/SagaManager/SagaManager/Program.cs +++ b/src/Services/SagaManager/SagaManager/Program.cs @@ -18,6 +18,7 @@ namespace SagaManager using Services; using Autofac.Extensions.DependencyInjection; using Autofac; + using System.Threading.Tasks; public class Program { @@ -25,7 +26,12 @@ namespace SagaManager public static void Main(string[] args) { - StartUp(); + MainAsync().Wait(); + } + + static async Task MainAsync() + { + StartUp(); IServiceCollection services = new ServiceCollection(); var serviceProvider = ConfigureServices(services); @@ -39,7 +45,7 @@ namespace SagaManager while (true) { sagaManagerService.CheckFinishedGracePeriodOrders(); - System.Threading.Thread.Sleep(30000); + await Task.Delay(30000); } } From 7c27ac498b0188e7a1fe7dae727683fad53c20d9 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:17:16 +0200 Subject: [PATCH 09/10] Add new methods to order aggregate root and modify saga process --- .../Ordering.API/Application/Sagas/Saga.cs | 5 -- .../AggregatesModel/OrderAggregate/Order.cs | 64 +++++++++++++++++-- .../OrderAggregate/OrderStatus.cs | 4 +- ...sChangedToAwaitingValidationDomainEvent.cs | 23 +++++++ .../OrderStatusChangedToPaidDomainEvent.cs | 23 +++++++ ...tatusChangedToStockConfirmedDomainEvent.cs | 16 +++++ .../OrderStockMethodVerifiedDomainEvent.cs | 24 ------- 7 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs create mode 100644 src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs create mode 100644 src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs delete mode 100644 src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs diff --git a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs index caaa3fa37..b03fb18fa 100644 --- a/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs +++ b/src/Services/Ordering/Ordering.API/Application/Sagas/Saga.cs @@ -17,10 +17,5 @@ namespace Ordering.API.Application.Sagas public abstract TEntity FindSagaById(int id); public abstract Task SaveChangesAsync(); - //{ - // var ctx = context ?? _dbContext; - // var result = await ctx.SaveChangesAsync(); - // return result > 0; - //} } } diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index e8bc2b42b..887900f90 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -1,5 +1,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork; using Ordering.Domain.Events; +using Ordering.Domain.Exceptions; using System; using System.Collections.Generic; using System.Linq; @@ -93,18 +94,38 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O _buyerId = id; } - public void SetOrderStatusId(int id) + #region Status Changes + public void SetSubmitedStatus() { - _orderStatusId = id; + _orderStatusId = OrderStatus.Submited.Id; + } + + public void SetAwaitingValidationStatus() + { + if (_orderStatusId != OrderStatus.Submited.Id) + { + StatusChangeException(); + } + + _orderStatusId = OrderStatus.AwaitingValidation.Id; + + AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, OrderItems)); } - public void SetOrderStockConfirmed(IEnumerable orderStockNotConfirmedItems = null) + public void SetStockConfirmedStatus(IEnumerable orderStockNotConfirmedItems = null) { - if(orderStockNotConfirmedItems is null) + if (_orderStatusId != OrderStatus.AwaitingValidation.Id) { - OrderStatus = OrderStatus.StockValidated; + StatusChangeException(); + } + + if (orderStockNotConfirmedItems is null) + { + OrderStatus = OrderStatus.StockConfirmed; _description = "All the items were confirmed with available stock."; + + AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); } else { @@ -117,10 +138,36 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O var itemsStockNotConfirmedDescription = string.Join(", ", itemsStockNotConfirmedProductNames); _description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription})."; } + } + + public void SetPaidStatus() + { + if (_orderStatusId != OrderStatus.StockConfirmed.Id) + { + StatusChangeException(); + } + + _orderStatusId = OrderStatus.Paid.Id; + _description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\""; + + AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems)); + } + + public void SetShippedStatus() + { + if (_orderStatusId != OrderStatus.Paid.Id) + { + StatusChangeException(); + } - AddDomainEvent(new OrderStockConfirmedDomainEvent(Id, OrderStatus)); + _orderStatusId = OrderStatus.Shipped.Id; + _description = ""; + + //Call Domain Event } + #endregion + private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) { @@ -130,6 +177,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O this.AddDomainEvent(orderStartedDomainEvent); } + + private void StatusChangeException() + { + throw new OrderingDomainException("Not able to process order event. Reason: no valid order status change"); + } } } diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs index 73178cbe5..02891fb58 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/OrderStatus.cs @@ -12,7 +12,7 @@ { public static OrderStatus Submited = new OrderStatus(1, nameof(Submited).ToLowerInvariant()); public static OrderStatus AwaitingValidation = new OrderStatus(2, nameof(AwaitingValidation).ToLowerInvariant()); - public static OrderStatus StockValidated = new OrderStatus(3, nameof(StockValidated).ToLowerInvariant()); + public static OrderStatus StockConfirmed = new OrderStatus(3, nameof(StockConfirmed).ToLowerInvariant()); public static OrderStatus Paid = new OrderStatus(4, nameof(Paid).ToLowerInvariant()); public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant()); public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant()); @@ -27,7 +27,7 @@ } public static IEnumerable List() => - new[] { Submited, AwaitingValidation, StockValidated, Paid, Shipped, Cancelled }; + new[] { Submited, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled }; public static OrderStatus FromName(string name) { diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs new file mode 100644 index 000000000..e324ecfa0 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToAwaitingValidationDomainEvent.cs @@ -0,0 +1,23 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using System.Collections.Generic; + + /// + /// Event used when the grace period order is confirmed + /// + public class OrderStatusChangedToAwaitingValidationDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + public IEnumerable OrderItems { get; } + + public OrderStatusChangedToAwaitingValidationDomainEvent(int orderId, + IEnumerable orderItems) + { + OrderId = orderId; + OrderItems = orderItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs new file mode 100644 index 000000000..743770507 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToPaidDomainEvent.cs @@ -0,0 +1,23 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; + using System.Collections.Generic; + + /// + /// Event used when the order is paid + /// + public class OrderStatusChangedToPaidDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + public IEnumerable OrderItems { get; } + + public OrderStatusChangedToPaidDomainEvent(int orderId, + IEnumerable orderItems) + { + OrderId = orderId; + OrderItems = orderItems; + } + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs new file mode 100644 index 000000000..2e9b2bab5 --- /dev/null +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderStatusChangedToStockConfirmedDomainEvent.cs @@ -0,0 +1,16 @@ +namespace Ordering.Domain.Events +{ + using MediatR; + + /// + /// Event used when the order stock items are confirmed + /// + public class OrderStatusChangedToStockConfirmedDomainEvent + : IAsyncNotification + { + public int OrderId { get; } + + public OrderStatusChangedToStockConfirmedDomainEvent(int orderId) + => OrderId = orderId; + } +} \ No newline at end of file diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs deleted file mode 100644 index 86f9c34d4..000000000 --- a/src/Services/Ordering/Ordering.Domain/Events/OrderStockMethodVerifiedDomainEvent.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate; - -namespace Ordering.Domain.Events -{ - using MediatR; - using System.Collections.Generic; - - /// - /// Event used when the order stock items are verified - /// - public class OrderStockConfirmedDomainEvent - : IAsyncNotification - { - public int OrderId { get; } - public OrderStatus OrderStatus { get; } - - public OrderStockConfirmedDomainEvent(int orderId, - OrderStatus orderStatus) - { - OrderId = orderId; - OrderStatus = orderStatus; - } - } -} \ No newline at end of file From 0ac19b8b3767e902cd3e9defa7c43c2f741f6f34 Mon Sep 17 00:00:00 2001 From: Christian Arenas Date: Mon, 15 May 2017 19:18:00 +0200 Subject: [PATCH 10/10] Fix bad namespace from CommandHandler --- src/Services/Catalog/Catalog.API/Startup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index e224dea0a..22dd201d0 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -16,7 +16,7 @@ using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.Commands; using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents; - using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandsHandlers; + using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationCommands.CommandHandlers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks;