diff --git a/docker-compose.yml b/docker-compose.yml index 788cfc264..09380e299 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: depends_on: - basket.data - identity.api + - rabbitmq catalog.api: image: eshop/catalog.api @@ -17,6 +18,7 @@ services: dockerfile: Dockerfile depends_on: - sql.data + - rabbitmq identity.api: image: eshop/identity.api diff --git a/eShopOnContainers-ServicesAndWebApps.sln b/eShopOnContainers-ServicesAndWebApps.sln index c92dc8c7d..539aec7b0 100644 --- a/eShopOnContainers-ServicesAndWebApps.sln +++ b/eShopOnContainers-ServicesAndWebApps.sln @@ -48,6 +48,10 @@ Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-co EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{F16E3C6A-1C94-4EAB-BE91-099618060B68}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{47857844-D05A-4C37-BFB2-AF19B7EC418D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "src\Services\Common\Infrastructure\Infrastructure.csproj", "{B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -494,6 +498,54 @@ Global {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x64.Build.0 = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.ActiveCfg = Release|Any CPU {F16E3C6A-1C94-4EAB-BE91-099618060B68}.Release|x86.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x64.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|ARM.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|ARM.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhone.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x64.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x64.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x86.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.AppStore|x86.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|ARM.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhone.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x64.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x64.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x86.ActiveCfg = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Debug|x86.Build.0 = Debug|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|Any CPU.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|ARM.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|ARM.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhone.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhone.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x64.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x64.Build.0 = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x86.ActiveCfg = Release|Any CPU + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -516,5 +568,7 @@ Global {7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870} {A579E108-5445-403D-A407-339AC4D1611B} = {24CD3B53-141E-4A07-9B0D-796641E1CF78} {F16E3C6A-1C94-4EAB-BE91-099618060B68} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04} + {47857844-D05A-4C37-BFB2-AF19B7EC418D} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} + {B08BA891-ABA2-4BD5-80E8-40B7546C3BE0} = {47857844-D05A-4C37-BFB2-AF19B7EC418D} EndGlobalSection EndGlobal diff --git a/src/Services/Catalog/Catalog.API/Catalog.API.csproj b/src/Services/Catalog/Catalog.API/Catalog.API.csproj index 6811e43cb..1c0fddf92 100644 --- a/src/Services/Catalog/Catalog.API/Catalog.API.csproj +++ b/src/Services/Catalog/Catalog.API/Catalog.API.csproj @@ -52,6 +52,10 @@ + + + + Always diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index 547cdfe21..bba7564e9 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -3,6 +3,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.Model; using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel; +using Microsoft.eShopOnContainers.Services.Common.Infrastructure; +using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog; using Microsoft.Extensions.Options; using System.Collections.Generic; using System.Linq; @@ -15,11 +17,13 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers { private readonly CatalogContext _context; private readonly IOptionsSnapshot _settings; + private readonly IEventBus _eventBus; - public CatalogController(CatalogContext context, IOptionsSnapshot settings) + public CatalogController(CatalogContext context, IOptionsSnapshot settings, IEventBus eventBus) { _context = context; _settings = settings; + _eventBus = eventBus; ((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; } @@ -41,7 +45,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers itemsOnPage = ComposePicUri(itemsOnPage); var model = new PaginatedItemsViewModel( - pageIndex, pageSize, totalItems, itemsOnPage); + pageIndex, pageSize, totalItems, itemsOnPage); return Ok(model); } @@ -99,7 +103,13 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers var model = new PaginatedItemsViewModel( pageIndex, pageSize, totalItems, itemsOnPage); - + + //hook to run integration tests until POST methods are created + if (catalogTypeId.HasValue && catalogTypeId == 1) + { + _eventBus.Publish(new CatalogPriceChanged()); + } + return Ok(model); } diff --git a/src/Services/Catalog/Catalog.API/Startup.cs b/src/Services/Catalog/Catalog.API/Startup.cs index fb6cc3907..c8ecf72fd 100644 --- a/src/Services/Catalog/Catalog.API/Startup.cs +++ b/src/Services/Catalog/Catalog.API/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; + using Microsoft.eShopOnContainers.Services.Common.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -73,6 +74,8 @@ .AllowCredentials()); }); + services.AddSingleton(); + services.AddMvc(); } diff --git a/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs new file mode 100644 index 000000000..ad22ae49f --- /dev/null +++ b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChanged.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog +{ + public class CatalogPriceChanged : IIntegrationEvent + { + private readonly string _eventName = "catalogpricechanged"; + + public string Name { + get + { + return _eventName; + } + } + + public string Message { get { return "CatalogPriceChanged!!"; } } + } +} diff --git a/src/Services/Common/Infrastructure/Catalog/CatalogPriceChangedHandler.cs b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChangedHandler.cs new file mode 100644 index 000000000..8fc045ba0 --- /dev/null +++ b/src/Services/Common/Infrastructure/Catalog/CatalogPriceChangedHandler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog +{ + public class CatalogPriceChangedHandler : IIntegrationEventHandler + { + public void Handle(CatalogPriceChanged @event) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Services/Common/Infrastructure/EventBus.cs b/src/Services/Common/Infrastructure/EventBus.cs new file mode 100644 index 000000000..42ef384f1 --- /dev/null +++ b/src/Services/Common/Infrastructure/EventBus.cs @@ -0,0 +1,101 @@ + +using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure +{ + public class EventBus : IEventBus + { + private readonly Dictionary> _handlers; + private readonly Dictionary> _listeners; + + public EventBus() + { + _handlers = new Dictionary>(); + _listeners = new Dictionary>(); + } + public void Publish(IIntegrationEvent @event) + { + var factory = new ConnectionFactory() { HostName = "172.20.0.1" }; + using (var connection = factory.CreateConnection()) + using (var channel = connection.CreateModel()) + { + channel.QueueDeclare(queue: @event.Name, + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + + string message = ((CatalogPriceChanged)@event).Message; + var body = Encoding.UTF8.GetBytes(message); + + channel.BasicPublish(exchange: "", + routingKey: @event.Name, + basicProperties: null, + body: body); + } + + } + + public void Subscribe(IIntegrationEventHandler handler) where T : IIntegrationEvent + { + var eventName = typeof(T).Name; + if (_handlers.ContainsKey(eventName)) + { + _handlers[eventName].Add(handler); + } + else + { + var factory = new ConnectionFactory() { HostName = "172.18.0.1" }; + var connection = factory.CreateConnection(); + var channel = connection.CreateModel(); + + channel.QueueDeclare(queue: eventName, + durable: false, + exclusive: false, + autoDelete: false, + arguments: null); + + var consumer = new EventingBasicConsumer(channel); + consumer.Received += (model, ea) => + { + var body = ea.Body; + var message = Encoding.UTF8.GetString(body); + }; + channel.BasicConsume(queue: "hello", + noAck: true, + consumer: consumer); + ; + + _listeners.Add(eventName, new Tuple(channel, connection)); + _handlers.Add(eventName, new List()); + _handlers[eventName].Add(handler); + } + + } + + public void Unsubscribe(IIntegrationEventHandler handler) where T : IIntegrationEvent + { + var eventName = typeof(T).Name; + if (_handlers.ContainsKey(eventName) && _handlers[eventName].Contains(handler)) + { + _handlers[eventName].Remove(handler); + + if (_handlers[eventName].Count == 0) + { + _handlers.Remove(eventName); + + var connectionItems =_listeners[eventName]; + _listeners.Remove(eventName); + + connectionItems.Item1.Close(); + connectionItems.Item2.Close(); + } + } + } + } +} diff --git a/src/Services/Common/Infrastructure/IEventBus.cs b/src/Services/Common/Infrastructure/IEventBus.cs new file mode 100644 index 000000000..5751f1b81 --- /dev/null +++ b/src/Services/Common/Infrastructure/IEventBus.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure +{ + public interface IEventBus + { + void Subscribe(IIntegrationEventHandler handler) where T: IIntegrationEvent; + void Unsubscribe(IIntegrationEventHandler handler) where T : IIntegrationEvent; + void Publish(IIntegrationEvent @event); + } +} diff --git a/src/Services/Common/Infrastructure/IIntegrationEvent.cs b/src/Services/Common/Infrastructure/IIntegrationEvent.cs new file mode 100644 index 000000000..9e92db3a4 --- /dev/null +++ b/src/Services/Common/Infrastructure/IIntegrationEvent.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure +{ + public interface IIntegrationEvent + { + string Name { get; } + } +} diff --git a/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs b/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs new file mode 100644 index 000000000..b2d902ca2 --- /dev/null +++ b/src/Services/Common/Infrastructure/IIntegrationEventHandler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure +{ + public interface IIntegrationEventHandler : IIntegrationEventHandler + where TIntegrationEvent: IIntegrationEvent + { + void Handle(TIntegrationEvent @event); + } + + public interface IIntegrationEventHandler { } +} diff --git a/src/Services/Common/Infrastructure/Infrastructure.csproj b/src/Services/Common/Infrastructure/Infrastructure.csproj new file mode 100644 index 000000000..fc7038ce9 --- /dev/null +++ b/src/Services/Common/Infrastructure/Infrastructure.csproj @@ -0,0 +1,10 @@ + + + netcoreapp1.1 + 1.1.0 + Microsoft.eShopOnContainers.Services.Common.Infrastructure + + + + + \ No newline at end of file