From 4d1269b8f2424d7629879b8819d93be8168b4a94 Mon Sep 17 00:00:00 2001 From: dsanz Date: Fri, 10 Mar 2017 18:34:58 +0100 Subject: [PATCH] Add handler logic for basket repository. Add Post to CatalogController (only for price update). --- .../Events/CatalogPriceChangedHandler.cs | 31 ++++++++++++--- .../Basket/Basket.API/Model/BasketItem.cs | 1 + .../Basket.API/Model/IBasketRepository.cs | 1 + .../Basket.API/Model/RedisBasketRepository.cs | 38 +++++++++++++++++-- src/Services/Basket/Basket.API/Startup.cs | 19 +++++++++- .../Controllers/CatalogController.cs | 26 ++++++++++++- .../Catalog/CatalogPriceChanged.cs | 9 +++-- .../Common/Infrastructure/EventBus.cs | 5 ++- .../IIntegrationEventHandler.cs | 3 +- 9 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/Services/Basket/Basket.API/Events/CatalogPriceChangedHandler.cs b/src/Services/Basket/Basket.API/Events/CatalogPriceChangedHandler.cs index 67fc6616f..db116b0c4 100644 --- a/src/Services/Basket/Basket.API/Events/CatalogPriceChangedHandler.cs +++ b/src/Services/Basket/Basket.API/Events/CatalogPriceChangedHandler.cs @@ -11,15 +11,36 @@ namespace Basket.API.Events public class CatalogPriceChangedHandler : IIntegrationEventHandler { private readonly IBasketRepository _repository; - public CatalogPriceChangedHandler() + public CatalogPriceChangedHandler(IBasketRepository repository) { - //_repository = repository; + _repository = repository; } - public void Handle(CatalogPriceChanged @event) + public async Task Handle(CatalogPriceChanged @event) { - - } + var userIds = await _repository.GetUsers(); + foreach (var id in userIds) + { + var basket = await _repository.GetBasket(id); + await UpdateBasket(@event.ItemId, @event.NewPrice, basket); + } + } + + private async Task UpdateBasket(int itemId, decimal newPrice, CustomerBasket basket) + { + //TODO here seems to be a problem with the format + var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.Id) == itemId).ToList(); + if (itemsToUpdate != null) + { + foreach (var item in itemsToUpdate) + { + var originalPrice = item.UnitPrice; + item.UnitPrice = newPrice; + item.OldUnitPrice = originalPrice; + } + await _repository.UpdateBasket(basket); + } + } } } diff --git a/src/Services/Basket/Basket.API/Model/BasketItem.cs b/src/Services/Basket/Basket.API/Model/BasketItem.cs index c3f9b6212..76835ade9 100644 --- a/src/Services/Basket/Basket.API/Model/BasketItem.cs +++ b/src/Services/Basket/Basket.API/Model/BasketItem.cs @@ -11,6 +11,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public string ProductId { get; set; } public string ProductName { get; set; } public decimal UnitPrice { get; set; } + public decimal OldUnitPrice { get; set; } public int Quantity { get; set; } public string PictureUrl { get; set; } } diff --git a/src/Services/Basket/Basket.API/Model/IBasketRepository.cs b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs index 3f0b99acf..017de8d51 100644 --- a/src/Services/Basket/Basket.API/Model/IBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs @@ -8,6 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model public interface IBasketRepository { Task GetBasket(string customerId); + Task> GetUsers(); Task UpdateBasket(CustomerBasket basket); Task DeleteBasket(string id); } diff --git a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs index 19d8e7055..fc5c256f8 100644 --- a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs @@ -31,6 +31,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model return await database.KeyDeleteAsync(id.ToString()); } + public async Task> GetUsers() + { + var server = await GetServer(); + + IEnumerable data = server.Keys(); + if (data == null) + { + return null; + } + return data.Select(k => k.ToString()); + } + public async Task GetBasket(string customerId) { var database = await GetDatabase(); @@ -63,14 +75,32 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { if (_redis == null) { - //TODO: Need to make this more robust. Also want to understand why the static connection method cannot accept dns names. - var ips = await Dns.GetHostAddressesAsync(_settings.ConnectionString); - _logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}"); - _redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString()); + await ConnectToRedisAsync(); } return _redis.GetDatabase(); } + + private async Task GetServer() + { + if (_redis == null) + { + await ConnectToRedisAsync(); + } + var endpoint = _redis.GetEndPoints(); + + return _redis.GetServer(endpoint.First()); + } + + private async Task ConnectToRedisAsync() + { + //TODO: Need to make this more robust. Also want to understand why the static connection method cannot accept dns names. + var ips = await Dns.GetHostAddressesAsync(_settings.ConnectionString); + _logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}"); + _redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString()); + } + + } } diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 2eb6a36c1..f7fa06df8 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -79,9 +79,24 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API }); services.AddTransient(); - var eventBus = new EventBus(); + services.AddTransient, CatalogPriceChangedHandler>(); + + var eventBus = new EventBus(); services.AddSingleton(eventBus); - eventBus.Subscribe(new CatalogPriceChangedHandler()); + + var serviceProvider = services.BuildServiceProvider(); + var catalogPriceHandler = serviceProvider.GetService>(); + eventBus.Subscribe(catalogPriceHandler); + + //var container = new ContainerBuilder(); + //container.Populate(services); + //container.RegisterModule(new ApplicationModule()); + + //return new AutofacServiceProvider(container.Build()); + + //var eventBus = new EventBus(); + //services.AddSingleton(eventBus); + //eventBus.Subscribe(new CatalogPriceChangedHandler(new RedisBasketRepository()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index 3558c55f5..9d8cc0b11 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -107,7 +107,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers //hook to run integration tests until POST methods are created if (catalogTypeId.HasValue && catalogTypeId == 1) { - _eventBus.Publish(new CatalogPriceChanged(2, 10.4M)); + _eventBus.Publish(new CatalogPriceChanged(2, 10.4M, 8.4M)); } return Ok(model); @@ -135,6 +135,30 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers return Ok(items); } + [HttpPost] + public async Task Post([FromBody]CatalogItem value) + { + var item = await _context.CatalogItems.SingleOrDefaultAsync(i => i.Id == value.Id); + + if (item == null) + { + return NotFound(); + } + + if (item.Price != value.Price) + { + var oldPrice = item.Price; + item.Price = value.Price; + + _context.CatalogItems.Update(item); + await _context.SaveChangesAsync(); + + _eventBus.Publish(new CatalogPriceChanged(item.Id, item.Price, oldPrice)); + } + + return Ok(); + } + private List ComposePicUri(List items) { var baseUri = _settings.Value.ExternalCatalogBaseUrl; items.ForEach(x => diff --git a/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs index 6e5715925..427aa69c2 100644 --- a/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs +++ b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs @@ -5,17 +5,18 @@ using System.Text; namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog { public class CatalogPriceChanged : IIntegrationEvent - { - public string Message { get { return "CatalogPriceChanged here!!"; } } - + { public int ItemId { get; private set; } public decimal NewPrice { get; private set; } - public CatalogPriceChanged(int itemId, decimal newPrice) + public decimal OldPrice { get; set; } + + public CatalogPriceChanged(int itemId, decimal newPrice, decimal oldPrice) { ItemId = itemId; NewPrice = newPrice; + OldPrice = oldPrice; } } } diff --git a/src/Services/Common/Infrastructure/EventBus.cs b/src/Services/Common/Infrastructure/EventBus.cs index a606a6d33..dd273d571 100644 --- a/src/Services/Common/Infrastructure/EventBus.cs +++ b/src/Services/Common/Infrastructure/EventBus.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure { @@ -116,7 +117,7 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure } var consumer = new EventingBasicConsumer(channel); - consumer.Received += (model, ea) => + consumer.Received += async (model, ea) => { var eventName = ea.RoutingKey; if (_handlers.ContainsKey(eventName)) @@ -132,7 +133,7 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure foreach (var handler in handlers) { - concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); + await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); } } }; diff --git a/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs b/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs index 49d194ecb..6824a1665 100644 --- a/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs +++ b/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure { public interface IIntegrationEventHandler : IIntegrationEventHandler where TIntegrationEvent: IIntegrationEvent { - void Handle(TIntegrationEvent @event); + Task Handle(TIntegrationEvent @event); } public interface IIntegrationEventHandler