diff --git a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj index 65510f096..ad6867741 100644 --- a/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj +++ b/src/BuildingBlocks/EventBus/EventBus/EventBus.csproj @@ -8,7 +8,6 @@ - diff --git a/src/BuildingBlocks/EventBus/EventBus/Events/EventStateEnum.cs b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/EventStateEnum.cs similarity index 91% rename from src/BuildingBlocks/EventBus/EventBus/Events/EventStateEnum.cs rename to src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/EventStateEnum.cs index 49be3cc4e..41ddc119c 100644 --- a/src/BuildingBlocks/EventBus/EventBus/Events/EventStateEnum.cs +++ b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/EventStateEnum.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events +namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog { public enum EventStateEnum { diff --git a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLogEntry.cs b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/IntegrationEventLogEntry.cs similarity index 97% rename from src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLogEntry.cs rename to src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/IntegrationEventLogEntry.cs index 3feb33210..a74c600e4 100644 --- a/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLogEntry.cs +++ b/src/BuildingBlocks/EventBus/EventBus/Events/IntegrationEventLog/IntegrationEventLogEntry.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Newtonsoft.Json; -namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events +namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog { public class IntegrationEventLogEntry { diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs similarity index 83% rename from src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedEventHandler.cs rename to src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs index f32b71af3..84d874271 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs @@ -6,15 +6,15 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling { - public class ProductPriceChangedEventHandler : IIntegrationEventHandler + public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler { private readonly IBasketRepository _repository; - public ProductPriceChangedEventHandler(IBasketRepository repository) + public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository) { _repository = repository; } - public async Task Handle(ProductPriceChangedEvent @event) + public async Task Handle(ProductPriceChangedIntegrationEvent @event) { var userIds = await _repository.GetUsers(); foreach (var id in userIds) diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs similarity index 81% rename from src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs rename to src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs index b3cc5796f..87d2e9e81 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs @@ -8,7 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even // 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. - public class ProductPriceChangedEvent : IntegrationEvent + public class ProductPriceChangedIntegrationEvent : IntegrationEvent { public int ProductId { get; private set; } @@ -16,7 +16,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even public decimal OldPrice { get; private set; } - public ProductPriceChangedEvent(int productId, decimal newPrice, decimal oldPrice) + public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice) { ProductId = productId; NewPrice = newPrice; diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 49197782f..db72792bd 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -77,7 +77,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API }); services.AddTransient(); - services.AddTransient, ProductPriceChangedEventHandler>(); + services.AddTransient, ProductPriceChangedIntegrationEventHandler>(); var serviceProvider = services.BuildServiceProvider(); var configuration = serviceProvider.GetRequiredService>().Value; @@ -103,9 +103,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API app.UseSwagger() .UseSwaggerUi(); - var catalogPriceHandler = app.ApplicationServices.GetService>(); + var catalogPriceHandler = app.ApplicationServices.GetService>(); var eventBus = app.ApplicationServices.GetRequiredService(); - eventBus.Subscribe(catalogPriceHandler); + eventBus.Subscribe(catalogPriceHandler); } diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index fe8ea6ef9..5cef06749 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -22,7 +22,6 @@ PreserveNewest - PreserveNewest diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index 9c3bd170e..431928e0b 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; -using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; using Microsoft.eShopOnContainers.Services.Catalog.API.Model; @@ -146,7 +146,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers item.Price = value.Price; _context.CatalogItems.Update(item); - var @event = new ProductPriceChangedEvent(item.Id, item.Price, oldPrice); + var @event = new ProductPriceChangedIntegrationEvent(item.Id, item.Price, oldPrice); var eventLogEntry = new IntegrationEventLogEntry(@event); _context.IntegrationEventLog.Add(eventLogEntry); diff --git a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs index 43ace7e6e..846b1dbb5 100644 --- a/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs +++ b/src/Services/Catalog/Catalog.API/Infrastructure/CatalogContext.cs @@ -2,8 +2,8 @@ { using EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore; - using Model; - using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using Model; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog; public class CatalogContext : DbContext { diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs.txt b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs.txt deleted file mode 100644 index 4ace69180..000000000 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs.txt +++ /dev/null @@ -1,3 +0,0 @@ - - -// To implement any future integration event handler here diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs similarity index 81% rename from src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs rename to src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs index c757259f9..10b8317da 100644 --- a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedEvent.cs +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs @@ -8,7 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Eve // 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. - public class ProductPriceChangedEvent : IntegrationEvent + public class ProductPriceChangedIntegrationEvent : IntegrationEvent { public int ProductId { get; private set; } @@ -16,7 +16,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Eve public decimal OldPrice { get; private set; } - public ProductPriceChangedEvent(int productId, decimal newPrice, decimal oldPrice) + public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice) { ProductId = productId; NewPrice = newPrice; diff --git a/src/Services/Ordering/Ordering.API/Application/EventHandlers/OrderCreatedEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCreatedDomainEventHandler.cs similarity index 74% rename from src/Services/Ordering/Ordering.API/Application/EventHandlers/OrderCreatedEventHandler.cs rename to src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCreatedDomainEventHandler.cs index 422a61c9b..8aed7f1b2 100644 --- a/src/Services/Ordering/Ordering.API/Application/EventHandlers/OrderCreatedEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCreatedDomainEventHandler.cs @@ -6,22 +6,22 @@ using Ordering.Domain.Events; using System; using System.Threading.Tasks; -namespace Ordering.API.Application.EventHandlers +namespace Ordering.API.Application.DomainEventHandlers { - public class OrderCreatedEventHandler : IAsyncNotificationHandler + public class OrderCreatedDomainEventHandler : IAsyncNotificationHandler { private readonly ILoggerFactory _logger; private readonly IBuyerRepository _buyerRepository; private readonly IIdentityService _identityService; - public OrderCreatedEventHandler(ILoggerFactory logger, IBuyerRepository buyerRepository, IIdentityService identityService) + public OrderCreatedDomainEventHandler(ILoggerFactory logger, IBuyerRepository buyerRepository, IIdentityService identityService) { _buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository)); _identityService = identityService ?? throw new ArgumentNullException(nameof(identityService)); _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; @@ -46,7 +46,7 @@ namespace Ordering.API.Application.EventHandlers await _buyerRepository.UnitOfWork .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}."); } } diff --git a/src/Services/Ordering/Ordering.API/Application/EventHandlers/PaymentMethodCheckedEventHandler.cs b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/PaymentMethodCheckedDomainEventHandler.cs similarity index 71% rename from src/Services/Ordering/Ordering.API/Application/EventHandlers/PaymentMethodCheckedEventHandler.cs rename to src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/PaymentMethodCheckedDomainEventHandler.cs index b72b89363..eb833f70e 100644 --- a/src/Services/Ordering/Ordering.API/Application/EventHandlers/PaymentMethodCheckedEventHandler.cs +++ b/src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/PaymentMethodCheckedDomainEventHandler.cs @@ -5,19 +5,19 @@ using Ordering.Domain.Events; using System; using System.Threading.Tasks; -namespace Ordering.API.Application.EventHandlers +namespace Ordering.API.Application.DomainEventHandlers { - public class PaymentMethodCheckedEventHandler : IAsyncNotificationHandler + public class PaymentMethodCheckedDomainEventHandler : IAsyncNotificationHandler { private readonly IOrderRepository _orderRepository; private readonly ILoggerFactory _logger; - public PaymentMethodCheckedEventHandler(IOrderRepository orderRepository, ILoggerFactory logger) + public PaymentMethodCheckedDomainEventHandler(IOrderRepository orderRepository, ILoggerFactory logger) { _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); _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); orderToUpdate.SetBuyerId(paymentMethodNotification.Buyer.Id); @@ -26,7 +26,7 @@ namespace Ordering.API.Application.EventHandlers await _orderRepository.UnitOfWork .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 }"); } } diff --git a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs index 8585b8aa9..8d76fd9f5 100644 --- a/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs +++ b/src/Services/Ordering/Ordering.API/Infrastructure/AutofacModules/MediatorModule.cs @@ -3,7 +3,7 @@ using Autofac.Core; using MediatR; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators; -using Ordering.API.Application.EventHandlers; +using Ordering.API.Application.DomainEventHandlers; using Ordering.Domain.Events; using System.Collections.Generic; using System.Linq; @@ -24,7 +24,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof .Select(i => new KeyedService("IAsyncRequestHandler", i))); builder - .RegisterAssemblyTypes(typeof(OrderCreatedEventHandler).GetTypeInfo().Assembly) + .RegisterAssemblyTypes(typeof(OrderCreatedDomainEventHandler).GetTypeInfo().Assembly) .Where(t => t.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>))) .AsImplementedInterfaces(); diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs index 64acbf7b7..cedb42c06 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs @@ -33,7 +33,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B if (existingPayment != null) { - AddEvent(new PaymentMethodChecked(this, existingPayment, orderId)); + AddDomainEvent(new PaymentMethodCheckedDomainEvent(this, existingPayment, orderId)); return existingPayment; } else @@ -41,7 +41,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B var payment = new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration); _paymentMethods.Add(payment); - AddEvent(new PaymentMethodChecked(this, payment, orderId)); + AddDomainEvent(new PaymentMethodCheckedDomainEvent(this, payment, orderId)); return payment; } } diff --git a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs index a1bb76cee..6ccece658 100644 --- a/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs +++ b/src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs @@ -51,7 +51,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O _orderStatusId = OrderStatus.InProcess.Id; _orderDate = DateTime.UtcNow; 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); } @@ -93,14 +96,14 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O _buyerId = id; } - private void AddCreatedOrderEvent(int cardTypeId, string cardNumber, + private void AddOrderCreatedDomainEvent(int cardTypeId, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) { - var @orderCreatedEvent = new OrderCreated( + var orderCreatedDomainEvent = new OrderCreatedDomainEvent( this, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); - AddEvent(@orderCreatedEvent); + AddDomainEvent(orderCreatedDomainEvent); } } } diff --git a/src/Services/Ordering/Ordering.Domain/Events/OrderCreated.cs b/src/Services/Ordering/Ordering.Domain/Events/OrderCreatedDomainEvent.cs similarity index 92% rename from src/Services/Ordering/Ordering.Domain/Events/OrderCreated.cs rename to src/Services/Ordering/Ordering.Domain/Events/OrderCreatedDomainEvent.cs index 489cc23d0..04fdb41db 100644 --- a/src/Services/Ordering/Ordering.Domain/Events/OrderCreated.cs +++ b/src/Services/Ordering/Ordering.Domain/Events/OrderCreatedDomainEvent.cs @@ -9,7 +9,7 @@ namespace Ordering.Domain.Events /// /// Event used when an order is created /// - public class OrderCreated + public class OrderCreatedDomainEvent : IAsyncNotification { public int CardTypeId { get; private set; } @@ -19,7 +19,7 @@ namespace Ordering.Domain.Events public DateTime CardExpiration { get; private set; } public Order Order { get; private set; } - public OrderCreated(Order order, + public OrderCreatedDomainEvent(Order order, int cardTypeId, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) diff --git a/src/Services/Ordering/Ordering.Domain/Events/PaymentMethodChecked.cs b/src/Services/Ordering/Ordering.Domain/Events/PaymentMethodCheckedDomainEvent.cs similarity index 78% rename from src/Services/Ordering/Ordering.Domain/Events/PaymentMethodChecked.cs rename to src/Services/Ordering/Ordering.Domain/Events/PaymentMethodCheckedDomainEvent.cs index 25c8d8111..a729361c7 100644 --- a/src/Services/Ordering/Ordering.Domain/Events/PaymentMethodChecked.cs +++ b/src/Services/Ordering/Ordering.Domain/Events/PaymentMethodCheckedDomainEvent.cs @@ -6,14 +6,14 @@ using System.Text; namespace Ordering.Domain.Events { - public class PaymentMethodChecked + public class PaymentMethodCheckedDomainEvent : IAsyncNotification { public Buyer Buyer { get; private set; } public PaymentMethod Payment { 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; Payment = payment; diff --git a/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs b/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs index e2c602300..7616a3230 100644 --- a/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs +++ b/src/Services/Ordering/Ordering.Domain/SeedWork/Entity.cs @@ -10,7 +10,7 @@ int? _requestedHashCode; int _Id; - private List _events; + private List _domainEvents; public virtual int Id { @@ -24,17 +24,17 @@ } } - public List Events => _events; - public void AddEvent(IAsyncNotification eventItem) + public List DomainEvents => _domainEvents; + public void AddDomainEvent(IAsyncNotification eventItem) { - _events = _events ?? new List(); - _events.Add(eventItem); + _domainEvents = _domainEvents ?? new List(); + _domainEvents.Add(eventItem); } - public void RemoveEvent(IAsyncNotification eventItem) + public void RemoveDomainEvent(IAsyncNotification eventItem) { - if (_events is null) return; - _events.Remove(eventItem); + if (_domainEvents is null) return; + _domainEvents.Remove(eventItem); } public bool IsTransient() diff --git a/src/Services/Ordering/Ordering.Infrastructure/MediatorExtension.cs b/src/Services/Ordering/Ordering.Infrastructure/MediatorExtension.cs index 5949f00b4..21fc5e21f 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/MediatorExtension.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/MediatorExtension.cs @@ -10,9 +10,9 @@ namespace Ordering.Infrastructure { public static async Task RaiseDomainEventsAsync(this IMediator mediator, OrderingContext ctx) { - var domainEntities = ctx.ChangeTracker.Entries().Where(x => x.Entity.Events != null && x.Entity.Events.Any()); - var domainEvents = domainEntities.SelectMany(x => x.Entity.Events).ToList(); - domainEntities.ToList().ForEach(entity => entity.Entity.Events.Clear()); + var domainEntities = ctx.ChangeTracker.Entries().Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()); + var domainEvents = domainEntities.SelectMany(x => x.Entity.DomainEvents).ToList(); + domainEntities.ToList().ForEach(entity => entity.Entity.DomainEvents.Clear()); var tasks = domainEvents .Select(async (domainEvent) => { diff --git a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs index 504ed0ab7..56790185e 100644 --- a/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs +++ b/src/Services/Ordering/Ordering.Infrastructure/OrderingContext.cs @@ -74,7 +74,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure buyerConfiguration.HasKey(b => b.Id); - buyerConfiguration.Ignore(b => b.Events); + buyerConfiguration.Ignore(b => b.DomainEvents); buyerConfiguration.Property(b => b.Id) .ForSqlServerUseSequenceHiLo("buyerseq", DEFAULT_SCHEMA); @@ -102,7 +102,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure paymentConfiguration.HasKey(b => b.Id); - paymentConfiguration.Ignore(b => b.Events); + paymentConfiguration.Ignore(b => b.DomainEvents); paymentConfiguration.Property(b => b.Id) .ForSqlServerUseSequenceHiLo("paymentseq", DEFAULT_SCHEMA); @@ -139,7 +139,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure orderConfiguration.HasKey(o => o.Id); - orderConfiguration.Ignore(b => b.Events); + orderConfiguration.Ignore(b => b.DomainEvents); orderConfiguration.Property(o => o.Id) .ForSqlServerUseSequenceHiLo("orderseq", DEFAULT_SCHEMA); @@ -176,7 +176,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure orderItemConfiguration.HasKey(o => o.Id); - orderItemConfiguration.Ignore(b => b.Events); + orderItemConfiguration.Ignore(b => b.DomainEvents); orderItemConfiguration.Property(o => o.Id) .ForSqlServerUseSequenceHiLo("orderitemseq"); @@ -238,6 +238,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure public async Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)) { var result = await base.SaveChangesAsync(); + + // Dispatch the Domain Events collection right after saving/commiting data into the database await _mediator.RaiseDomainEventsAsync(this); return result; } diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index fc435ef6b..3d9317ae6 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -7,6 +7,7 @@ using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.AspNetCore.Authorization; using System.Net.Http; +using Polly.CircuitBreaker; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { @@ -37,18 +38,24 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers [HttpPost] public async Task Create(Order model, string action) { - if (ModelState.IsValid) + try { - var user = _appUserParser.Parse(HttpContext.User); - await _orderSvc.CreateOrder(model); + if (ModelState.IsValid) + { + var user = _appUserParser.Parse(HttpContext.User); + await _orderSvc.CreateOrder(model); - //Empty basket for current user. - await _basketSvc.CleanBasket(user); + //Empty basket for current user. + await _basketSvc.CleanBasket(user); - //Redirect to historic list. - return RedirectToAction("Index"); + //Redirect to historic list. + return RedirectToAction("Index"); + } + } + catch(BrokenCircuitException ex) + { + ModelState.AddModelError("Error", "Not possible to create a new order, please try later on"); } - return View(model); } diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs index c5b1bf0bc..bcb138b87 100644 --- a/src/Web/WebMVC/Services/BasketService.cs +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -1,29 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.eShopOnContainers.WebMVC.ViewModels; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; -using System.Net.Http; +using Microsoft.eShopOnContainers.WebMVC.ViewModels; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using Microsoft.AspNetCore.Authentication; -using Microsoft.eShopOnContainers.WebMVC.Extensions; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using WebMVC.Services.Utilities; namespace Microsoft.eShopOnContainers.WebMVC.Services { public class BasketService : IBasketService { private readonly IOptionsSnapshot _settings; - private HttpClient _apiClient; + private IHttpClient _apiClient; private readonly string _remoteServiceBaseUrl; private IHttpContextAccessor _httpContextAccesor; - public BasketService(IOptionsSnapshot settings, IHttpContextAccessor httpContextAccesor) + public BasketService(IOptionsSnapshot settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient) { _settings = settings; _remoteServiceBaseUrl = _settings.Value.BasketUrl; _httpContextAccesor = httpContextAccesor; + _apiClient = httpClient; } public async Task GetBasket(ApplicationUser user) @@ -31,8 +31,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}"; var dataString = await _apiClient.GetStringAsync(basketUrl); @@ -52,13 +51,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var basketUrl = _remoteServiceBaseUrl; - StringContent content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json"); - var response = await _apiClient.PostAsync(basketUrl, content); + + var response = await _apiClient.PostAsync(basketUrl, basket); return basket; } @@ -120,8 +118,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var basketUrl = $"{_remoteServiceBaseUrl}/{user.Id.ToString()}"; var response = await _apiClient.DeleteAsync(basketUrl); diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index 2c2035873..83b139c1f 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -1,35 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.eShopOnContainers.WebMVC.ViewModels; -using Microsoft.CodeAnalysis.Options; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System.Net.Http; -using Microsoft.AspNetCore.Mvc.Rendering; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Threading.Tasks; +using WebMVC.Services.Utilities; namespace Microsoft.eShopOnContainers.WebMVC.Services { public class CatalogService : ICatalogService { private readonly IOptionsSnapshot _settings; - private HttpClient _apiClient; + private IHttpClient _apiClient; private readonly string _remoteServiceBaseUrl; - public CatalogService(IOptionsSnapshot settings, ILoggerFactory loggerFactory) { + public CatalogService(IOptionsSnapshot settings, ILoggerFactory loggerFactory, IHttpClient httpClient) { _settings = settings; _remoteServiceBaseUrl = $"{_settings.Value.CatalogUrl}/api/v1/catalog/"; - + _apiClient = httpClient; var log = loggerFactory.CreateLogger("catalog service"); log.LogDebug(settings.Value.CatalogUrl); } public async Task GetCatalogItems(int page,int take, int? brand, int? type) { - _apiClient = new HttpClient(); var itemsQs = $"items?pageIndex={page}&pageSize={take}"; var filterQs = ""; @@ -45,16 +41,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var dataString = ""; // - // Using HttpClient with Retry and Exponential Backoff + // Using a HttpClient wrapper with Retry and Exponential Backoff // - var retry = new RetryWithExponentialBackoff(); - await retry.RunAsync(async () => - { - // work with HttpClient call - dataString = await _apiClient.GetStringAsync(catalogUrl); - }); + dataString = await _apiClient.GetStringAsync(catalogUrl); - //var dataString = await _apiClient.GetStringAsync(catalogUrl); var response = JsonConvert.DeserializeObject(dataString); return response; @@ -62,7 +52,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task> GetBrands() { - _apiClient = new HttpClient(); var url = $"{_remoteServiceBaseUrl}catalogBrands"; var dataString = await _apiClient.GetStringAsync(url); @@ -81,7 +70,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public async Task> GetTypes() { - _apiClient = new HttpClient(); var url = $"{_remoteServiceBaseUrl}catalogTypes"; var dataString = await _apiClient.GetStringAsync(url); diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index 184592839..d53db3090 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -8,30 +8,30 @@ using Microsoft.Extensions.Options; using System.Net.Http; using Newtonsoft.Json; using Microsoft.AspNetCore.Authentication; +using WebMVC.Services.Utilities; namespace Microsoft.eShopOnContainers.WebMVC.Services { public class OrderingService : IOrderingService { - private HttpClient _apiClient; + private IHttpClient _apiClient; private readonly string _remoteServiceBaseUrl; private readonly IOptionsSnapshot _settings; private readonly IHttpContextAccessor _httpContextAccesor; - public OrderingService(IOptionsSnapshot settings, IHttpContextAccessor httpContextAccesor) + public OrderingService(IOptionsSnapshot settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient) { _remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders"; _settings = settings; _httpContextAccesor = httpContextAccesor; + _apiClient = httpClient; } async public Task GetOrder(ApplicationUser user, string Id) { var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}"; var dataString = await _apiClient.GetStringAsync(ordersUrl); @@ -46,8 +46,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var ordersUrl = _remoteServiceBaseUrl; var dataString = await _apiClient.GetStringAsync(ordersUrl); @@ -77,17 +76,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services var context = _httpContextAccesor.HttpContext; var token = await context.Authentication.GetTokenAsync("access_token"); - _apiClient = new HttpClient(); - _apiClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); - _apiClient.DefaultRequestHeaders.Add("x-requestid", order.RequestId.ToString()); + _apiClient.Inst.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); + _apiClient.Inst.DefaultRequestHeaders.Add("x-requestid", order.RequestId.ToString()); + var ordersUrl = $"{_remoteServiceBaseUrl}/new"; order.CardTypeId = 1; order.CardExpirationApiFormat(); SetFakeIdToProducts(order); - - StringContent content = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json"); - - var response = await _apiClient.PostAsync(ordersUrl, content); + + var response = await _apiClient.PostAsync(ordersUrl, order); if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError) throw new Exception("Error creating order, try later"); diff --git a/src/Web/WebMVC/Services/Utilities/HttpApiClient.cs b/src/Web/WebMVC/Services/Utilities/HttpApiClient.cs new file mode 100644 index 000000000..8b142f393 --- /dev/null +++ b/src/Web/WebMVC/Services/Utilities/HttpApiClient.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Net.Http; +using System.Threading.Tasks; + +namespace WebMVC.Services.Utilities +{ + public class HttpApiClient : IHttpClient + { + private HttpClient _client; + private ILogger _logger; + public HttpClient Inst => _client; + public HttpApiClient() + { + _client = new HttpClient(); + _logger = new LoggerFactory().CreateLogger(nameof(HttpApiClientWrapper)); + } + + public async Task GetStringAsync(string uri) + { + return await HttpInvoker(async () => + await _client.GetStringAsync(uri)); + } + + public async Task PostAsync(string uri, T item) + { + var contentString = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"); + return await HttpInvoker(async () => + await _client.PostAsync(uri, contentString)); + } + + public async Task DeleteAsync(string uri) + { + return await HttpInvoker(async () => + await _client.DeleteAsync(uri)); + } + + private async Task HttpInvoker(Func> action) + { + return await action(); + } + } +} + diff --git a/src/Web/WebMVC/Services/Utilities/HttpApiClientWrapper.cs b/src/Web/WebMVC/Services/Utilities/HttpApiClientWrapper.cs new file mode 100644 index 000000000..dba0db9df --- /dev/null +++ b/src/Web/WebMVC/Services/Utilities/HttpApiClientWrapper.cs @@ -0,0 +1,99 @@ +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Polly; +using Polly.Wrap; +using System; +using System.Net.Http; +using System.Threading.Tasks; + +namespace WebMVC.Services.Utilities +{ + public class HttpApiClientWrapper : IHttpClient + { + private HttpClient _client; + private PolicyWrap _policyWrapper; + private ILogger _logger; + public HttpClient Inst => _client; + public HttpApiClientWrapper() + { + _client = new HttpClient(); + _logger = new LoggerFactory().CreateLogger(nameof(HttpApiClientWrapper)); + + // Add Policies to be applied + _policyWrapper = Policy.WrapAsync( + CreateRetryPolicy(), + CreateCircuitBreakerPolicy() + ); + } + + private Policy CreateCircuitBreakerPolicy() + { + return Policy + .Handle() + .CircuitBreakerAsync( + // number of exceptions before breaking circuit + 3, + // time circuit opened before retry + TimeSpan.FromMinutes(1), + (exception, duration) => { + // on circuit opened + _logger.LogTrace("Circuit breaker opened"); + }, + () => { + // on circuit closed + _logger.LogTrace("Circuit breaker reset"); + } + ); + } + + private Policy CreateRetryPolicy() + { + return Policy + .Handle() + .WaitAndRetryAsync( + // number of retries + 3, + // exponential backofff + retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), + // on retry + (exception, timeSpan, retryCount, context) => + { + _logger.LogTrace($"Retry {retryCount} " + + $"of {context.PolicyKey} " + + $"at {context.ExecutionKey}, " + + $"due to: {exception}."); + }); + } + + public async Task GetStringAsync(string uri) + { + return await HttpInvoker(async () => + await _client.GetStringAsync(uri)); + } + + public async Task PostAsync(string uri, T item) + { + // a new StringContent must be created for each retry + // as it is disposed after each call + return await HttpInvoker(async () => + await _client.PostAsync(uri, + new StringContent(JsonConvert.SerializeObject(item), + System.Text.Encoding.UTF8, "application/json"))); + } + + public async Task DeleteAsync(string uri) + { + return await HttpInvoker(async () => + await _client.DeleteAsync(uri)); + } + + private async Task HttpInvoker(Func> action) + { + // Executes the action applying all + // the policies defined in the wrapper + return await _policyWrapper + .ExecuteAsync(async () => await action()); + } + } + +} diff --git a/src/Web/WebMVC/Services/Utilities/IHttpClient.cs b/src/Web/WebMVC/Services/Utilities/IHttpClient.cs new file mode 100644 index 000000000..2a36466bc --- /dev/null +++ b/src/Web/WebMVC/Services/Utilities/IHttpClient.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace WebMVC.Services.Utilities +{ + public interface IHttpClient + { + HttpClient Inst { get; } + Task GetStringAsync(string uri); + Task PostAsync(string uri, T item); + Task DeleteAsync(string uri); + } +} diff --git a/src/Web/WebMVC/Services/Utilities/RetryWithExponentialBackoff.cs b/src/Web/WebMVC/Services/Utilities/RetryWithExponentialBackoff.cs deleted file mode 100644 index b9569c843..000000000 --- a/src/Web/WebMVC/Services/Utilities/RetryWithExponentialBackoff.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; - -namespace Microsoft.eShopOnContainers.WebMVC.Services -{ - /// - /// When working with cloud services and Docker containers, it's very important to always catch - /// TimeoutException, and retry the operation. - /// RetryWithExponentialBackoff makes it easy to implement such pattern. - /// Usage: - /// var retry = new RetryWithExponentialBackoff(); - /// await retry.RunAsync(async ()=> - /// { - /// // work with HttpClient - /// }); - /// - public sealed class RetryWithExponentialBackoff - { - private readonly int maxRetries, delayMilliseconds, maxDelayMilliseconds; - - public RetryWithExponentialBackoff(int maxRetries = 50, int delayMilliseconds = 200, int maxDelayMilliseconds = 2000) - { - this.maxRetries = maxRetries; - this.delayMilliseconds = delayMilliseconds; - this.maxDelayMilliseconds = maxDelayMilliseconds; - } - - public async Task RunAsync(Func func) - { - ExponentialBackoff backoff = new ExponentialBackoff(this.maxRetries, this.delayMilliseconds, this.maxDelayMilliseconds); - retry: - try - { - await func(); - } - catch (Exception ex) when (ex is TimeoutException || ex is System.Net.Http.HttpRequestException) - { - Debug.WriteLine("Exception raised is: " + ex.GetType().ToString() + " -- Message: " + ex.Message + " -- Inner Message: " + ex.InnerException.Message); - await backoff.Delay(); - goto retry; - } - } - } - - - /// - /// Usage: - /// ExponentialBackoff backoff = new ExponentialBackoff(3, 10, 100); - /// retry: - /// try { - /// // ... - /// } - /// catch (Exception ex) { - /// await backoff.Delay(cancellationToken); - /// goto retry; - /// } - /// - public struct ExponentialBackoff - { - private readonly int m_maxRetries, m_delayMilliseconds, m_maxDelayMilliseconds; - private int m_retries, m_pow; - - public ExponentialBackoff(int maxRetries, int delayMilliseconds, int maxDelayMilliseconds) - { - m_maxRetries = maxRetries; - m_delayMilliseconds = delayMilliseconds; - m_maxDelayMilliseconds = maxDelayMilliseconds; - m_retries = 0; - m_pow = 1; - } - - public Task Delay() - { - if (m_retries == m_maxRetries) - { - throw new TimeoutException("Max retry attempts exceeded."); - } - ++m_retries; - if (m_retries < 31) - { - m_pow = m_pow << 1; // m_pow = Pow(2, m_retries - 1) - } - int delay = Math.Min(m_delayMilliseconds * (m_pow - 1) / 2, m_maxDelayMilliseconds); - return Task.Delay(delay); - } - } -} diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 8bd7708d3..7888ae253 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.IdentityModel.Tokens; using Microsoft.AspNetCore.Http; using System.Threading; using Microsoft.Extensions.Options; +using WebMVC.Services.Utilities; namespace Microsoft.eShopOnContainers.WebMVC { @@ -43,14 +44,22 @@ namespace Microsoft.eShopOnContainers.WebMVC { services.AddMvc(); services.Configure(Configuration); - + // Add application services. - services.AddSingleton(); - + services.AddSingleton(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient, IdentityParser>(); + + if(Configuration.GetValue("ActivateCircuitBreaker") == bool.TrueString) + { + services.AddSingleton(); + } + else + { + services.AddSingleton(); + } } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Web/WebMVC/Views/Order/Create.cshtml b/src/Web/WebMVC/Views/Order/Create.cshtml index 58108b8e9..e05d3a7b7 100644 --- a/src/Web/WebMVC/Views/Order/Create.cshtml +++ b/src/Web/WebMVC/Views/Order/Create.cshtml @@ -11,6 +11,13 @@
+
+ @foreach (var error in ViewData.ModelState.Values.SelectMany(err => err.Errors)) { + + } +

Shipping address

diff --git a/src/Web/WebMVC/WebMVC.csproj b/src/Web/WebMVC/WebMVC.csproj index eb282bca3..e03f5e2c9 100644 --- a/src/Web/WebMVC/WebMVC.csproj +++ b/src/Web/WebMVC/WebMVC.csproj @@ -32,6 +32,7 @@ All + diff --git a/src/Web/WebMVC/appsettings.json b/src/Web/WebMVC/appsettings.json index 9fe15aa25..b848c11b1 100644 --- a/src/Web/WebMVC/appsettings.json +++ b/src/Web/WebMVC/appsettings.json @@ -4,6 +4,7 @@ "BasketUrl": "http://localhost:5103", "IdentityUrl": "http://localhost:5105", "CallBackUrl": "http://localhost:5100/", + "ActivateCircuitBreaker": "True", "Logging": { "IncludeScopes": false, "LogLevel": { diff --git a/test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs b/test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs index 2cf035205..0703ed197 100644 --- a/test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs +++ b/test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs @@ -122,6 +122,6 @@ public class BuyerAggregateTest fakeBuyer.AddPaymentMethod(cardTypeId, alias, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration, orderId); //Assert - Assert.Equal(fakeBuyer.Events.Count, expectedResult); + Assert.Equal(fakeBuyer.DomainEvents.Count, expectedResult); } } \ No newline at end of file diff --git a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs index dab34f528..c420951da 100644 --- a/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs +++ b/test/Services/UnitTest/Ordering/Domain/OrderAggregateTest.cs @@ -112,7 +112,7 @@ public class OrderAggregateTest var fakeOrder = new Order(new Address(street, city, state, country, zipcode), cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); //Assert - Assert.Equal(fakeOrder.Events.Count, expectedResult); + Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); } [Fact] @@ -133,9 +133,9 @@ public class OrderAggregateTest //Act 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.Equal(fakeOrder.Events.Count, expectedResult); + Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); } [Fact] @@ -153,13 +153,13 @@ public class OrderAggregateTest 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 OrderCreated(fakeOrder, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); + var @fakeEvent = new OrderCreatedDomainEvent(fakeOrder, cardTypeId, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration); var expectedResult = 1; //Act - fakeOrder.AddEvent(@fakeEvent); - fakeOrder.RemoveEvent(@fakeEvent); + fakeOrder.AddDomainEvent(@fakeEvent); + fakeOrder.RemoveDomainEvent(@fakeEvent); //Assert - Assert.Equal(fakeOrder.Events.Count, expectedResult); + Assert.Equal(fakeOrder.DomainEvents.Count, expectedResult); } } \ No newline at end of file