Add handler logic for basket repository. Add Post to CatalogController (only for price update).

This commit is contained in:
dsanz 2017-03-10 18:34:58 +01:00
parent 5b38a49f11
commit 4d1269b8f2
9 changed files with 114 additions and 19 deletions

View File

@ -11,14 +11,35 @@ namespace Basket.API.Events
public class CatalogPriceChangedHandler : IIntegrationEventHandler<CatalogPriceChanged> public class CatalogPriceChangedHandler : IIntegrationEventHandler<CatalogPriceChanged>
{ {
private readonly IBasketRepository _repository; 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);
}
} }
} }
} }

View File

@ -11,6 +11,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public string ProductId { get; set; } public string ProductId { get; set; }
public string ProductName { get; set; } public string ProductName { get; set; }
public decimal UnitPrice { get; set; } public decimal UnitPrice { get; set; }
public decimal OldUnitPrice { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public string PictureUrl { get; set; } public string PictureUrl { get; set; }
} }

View File

@ -8,6 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
public interface IBasketRepository public interface IBasketRepository
{ {
Task<CustomerBasket> GetBasket(string customerId); Task<CustomerBasket> GetBasket(string customerId);
Task<IEnumerable<string>> GetUsers();
Task<CustomerBasket> UpdateBasket(CustomerBasket basket); Task<CustomerBasket> UpdateBasket(CustomerBasket basket);
Task<bool> DeleteBasket(string id); Task<bool> DeleteBasket(string id);
} }

View File

@ -31,6 +31,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
return await database.KeyDeleteAsync(id.ToString()); return await database.KeyDeleteAsync(id.ToString());
} }
public async Task<IEnumerable<string>> GetUsers()
{
var server = await GetServer();
IEnumerable<RedisKey> data = server.Keys();
if (data == null)
{
return null;
}
return data.Select(k => k.ToString());
}
public async Task<CustomerBasket> GetBasket(string customerId) public async Task<CustomerBasket> GetBasket(string customerId)
{ {
var database = await GetDatabase(); var database = await GetDatabase();
@ -62,6 +74,25 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
private async Task<IDatabase> GetDatabase() private async Task<IDatabase> GetDatabase()
{ {
if (_redis == null) if (_redis == null)
{
await ConnectToRedisAsync();
}
return _redis.GetDatabase();
}
private async Task<IServer> 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. //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); var ips = await Dns.GetHostAddressesAsync(_settings.ConnectionString);
@ -69,8 +100,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
_redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString()); _redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString());
} }
return _redis.GetDatabase();
}
} }
} }

View File

@ -79,9 +79,24 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
}); });
services.AddTransient<IBasketRepository, RedisBasketRepository>(); services.AddTransient<IBasketRepository, RedisBasketRepository>();
services.AddTransient<IIntegrationEventHandler<CatalogPriceChanged>, CatalogPriceChangedHandler>();
var eventBus = new EventBus(); var eventBus = new EventBus();
services.AddSingleton<IEventBus>(eventBus); services.AddSingleton<IEventBus>(eventBus);
eventBus.Subscribe<CatalogPriceChanged>(new CatalogPriceChangedHandler());
var serviceProvider = services.BuildServiceProvider();
var catalogPriceHandler = serviceProvider.GetService<IIntegrationEventHandler<CatalogPriceChanged>>();
eventBus.Subscribe<CatalogPriceChanged>(catalogPriceHandler);
//var container = new ContainerBuilder();
//container.Populate(services);
//container.RegisterModule(new ApplicationModule());
//return new AutofacServiceProvider(container.Build());
//var eventBus = new EventBus();
//services.AddSingleton<IEventBus>(eventBus);
//eventBus.Subscribe<CatalogPriceChanged>(new CatalogPriceChangedHandler(new RedisBasketRepository());
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -107,7 +107,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
//hook to run integration tests until POST methods are created //hook to run integration tests until POST methods are created
if (catalogTypeId.HasValue && catalogTypeId == 1) if (catalogTypeId.HasValue && catalogTypeId == 1)
{ {
_eventBus.Publish(new CatalogPriceChanged(2, 10.4M)); _eventBus.Publish(new CatalogPriceChanged(2, 10.4M, 8.4M));
} }
return Ok(model); return Ok(model);
@ -135,6 +135,30 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
return Ok(items); return Ok(items);
} }
[HttpPost]
public async Task<IActionResult> 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<CatalogItem> ComposePicUri(List<CatalogItem> items) { private List<CatalogItem> ComposePicUri(List<CatalogItem> items) {
var baseUri = _settings.Value.ExternalCatalogBaseUrl; var baseUri = _settings.Value.ExternalCatalogBaseUrl;
items.ForEach(x => items.ForEach(x =>

View File

@ -6,16 +6,17 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog
{ {
public class CatalogPriceChanged : IIntegrationEvent public class CatalogPriceChanged : IIntegrationEvent
{ {
public string Message { get { return "CatalogPriceChanged here!!"; } }
public int ItemId { get; private set; } public int ItemId { get; private set; }
public decimal NewPrice { 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; ItemId = itemId;
NewPrice = newPrice; NewPrice = newPrice;
OldPrice = oldPrice;
} }
} }
} }

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
{ {
@ -116,7 +117,7 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
} }
var consumer = new EventingBasicConsumer(channel); var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) => consumer.Received += async (model, ea) =>
{ {
var eventName = ea.RoutingKey; var eventName = ea.RoutingKey;
if (_handlers.ContainsKey(eventName)) if (_handlers.ContainsKey(eventName))
@ -132,7 +133,7 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
foreach (var handler in handlers) foreach (var handler in handlers)
{ {
concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent }); await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
} }
} }
}; };

View File

@ -1,13 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
{ {
public interface IIntegrationEventHandler<in TIntegrationEvent> : IIntegrationEventHandler public interface IIntegrationEventHandler<in TIntegrationEvent> : IIntegrationEventHandler
where TIntegrationEvent: IIntegrationEvent where TIntegrationEvent: IIntegrationEvent
{ {
void Handle(TIntegrationEvent @event); Task Handle(TIntegrationEvent @event);
} }
public interface IIntegrationEventHandler public interface IIntegrationEventHandler