Add Basket handler and subscription to events. Change in EventBus to use broker and one message queue per microservice http://www.rabbitmq.com/tutorials/tutorial-four-dotnet.html
This commit is contained in:
parent
18a402044e
commit
5b38a49f11
@ -39,6 +39,10 @@
|
|||||||
<PackageReference Include="Swashbuckle" Version="6.0.0-beta902" />
|
<PackageReference Include="Swashbuckle" Version="6.0.0-beta902" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Infrastructure\Infrastructure.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Dockerfile">
|
<None Update="Dockerfile">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Common.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Basket.API.Events
|
||||||
|
{
|
||||||
|
public class CatalogPriceChangedHandler : IIntegrationEventHandler<CatalogPriceChanged>
|
||||||
|
{
|
||||||
|
private readonly IBasketRepository _repository;
|
||||||
|
public CatalogPriceChangedHandler()
|
||||||
|
{
|
||||||
|
//_repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(CatalogPriceChanged @event)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,9 @@ using Microsoft.Extensions.Options;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Swashbuckle.Swagger.Model;
|
using Swashbuckle.Swagger.Model;
|
||||||
using Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server;
|
using Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Common.Infrastructure;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
|
||||||
|
using Basket.API.Events;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||||
{
|
{
|
||||||
@ -76,6 +79,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
});
|
});
|
||||||
|
|
||||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||||
|
var eventBus = new EventBus();
|
||||||
|
services.AddSingleton<IEventBus>(eventBus);
|
||||||
|
eventBus.Subscribe<CatalogPriceChanged>(new CatalogPriceChangedHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -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());
|
_eventBus.Publish(new CatalogPriceChanged(2, 10.4M));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(model);
|
return Ok(model);
|
||||||
|
@ -6,15 +6,16 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog
|
|||||||
{
|
{
|
||||||
public class CatalogPriceChanged : IIntegrationEvent
|
public class CatalogPriceChanged : IIntegrationEvent
|
||||||
{
|
{
|
||||||
private readonly string _eventName = "catalogpricechanged";
|
public string Message { get { return "CatalogPriceChanged here!!"; } }
|
||||||
|
|
||||||
public string Name {
|
public int ItemId { get; private set; }
|
||||||
get
|
|
||||||
|
public decimal NewPrice { get; private set; }
|
||||||
|
|
||||||
|
public CatalogPriceChanged(int itemId, decimal newPrice)
|
||||||
{
|
{
|
||||||
return _eventName;
|
ItemId = itemId;
|
||||||
}
|
NewPrice = newPrice;
|
||||||
}
|
|
||||||
|
|
||||||
public string Message { get { return "CatalogPriceChanged!!"; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog
|
|
||||||
{
|
|
||||||
public class CatalogPriceChangedHandler : IIntegrationEventHandler<CatalogPriceChanged>
|
|
||||||
{
|
|
||||||
public void Handle(CatalogPriceChanged @event)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +1,47 @@
|
|||||||
|
|
||||||
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
|
using Microsoft.eShopOnContainers.Services.Common.Infrastructure.Catalog;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using RabbitMQ.Client.Events;
|
using RabbitMQ.Client.Events;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
||||||
{
|
{
|
||||||
public class EventBus : IEventBus
|
public class EventBus : IEventBus
|
||||||
{
|
{
|
||||||
|
private readonly string _brokerName = "event_bus";
|
||||||
private readonly Dictionary<string, List<IIntegrationEventHandler>> _handlers;
|
private readonly Dictionary<string, List<IIntegrationEventHandler>> _handlers;
|
||||||
private readonly Dictionary<string, Tuple<IModel, IConnection>> _listeners;
|
private readonly List<Type> _eventTypes;
|
||||||
|
|
||||||
|
private Tuple<IModel, IConnection> _connection;
|
||||||
|
private string _queueName;
|
||||||
|
|
||||||
|
|
||||||
public EventBus()
|
public EventBus()
|
||||||
{
|
{
|
||||||
_handlers = new Dictionary<string, List<IIntegrationEventHandler>>();
|
_handlers = new Dictionary<string, List<IIntegrationEventHandler>>();
|
||||||
_listeners = new Dictionary<string, Tuple<IModel, IConnection>>();
|
_eventTypes = new List<Type>();
|
||||||
}
|
}
|
||||||
public void Publish(IIntegrationEvent @event)
|
public void Publish(IIntegrationEvent @event)
|
||||||
{
|
{
|
||||||
|
var eventName = @event.GetType().Name;
|
||||||
var factory = new ConnectionFactory() { HostName = "172.20.0.1" };
|
var factory = new ConnectionFactory() { HostName = "172.20.0.1" };
|
||||||
using (var connection = factory.CreateConnection())
|
using (var connection = factory.CreateConnection())
|
||||||
using (var channel = connection.CreateModel())
|
using (var channel = connection.CreateModel())
|
||||||
{
|
{
|
||||||
channel.QueueDeclare(queue: @event.Name,
|
channel.ExchangeDeclare(exchange: _brokerName,
|
||||||
durable: false,
|
type: "direct");
|
||||||
exclusive: false,
|
|
||||||
autoDelete: false,
|
|
||||||
arguments: null);
|
|
||||||
|
|
||||||
string message = ((CatalogPriceChanged)@event).Message;
|
string message = JsonConvert.SerializeObject(@event);
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
var body = Encoding.UTF8.GetBytes(message);
|
||||||
|
|
||||||
channel.BasicPublish(exchange: "",
|
channel.BasicPublish(exchange: _brokerName,
|
||||||
routingKey: @event.Name,
|
routingKey: eventName,
|
||||||
basicProperties: null,
|
basicProperties: null,
|
||||||
body: body);
|
body: body);
|
||||||
}
|
}
|
||||||
@ -50,30 +57,14 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var factory = new ConnectionFactory() { HostName = "172.18.0.1" };
|
var channel = GetChannel();
|
||||||
var connection = factory.CreateConnection();
|
channel.QueueBind(queue: _queueName,
|
||||||
var channel = connection.CreateModel();
|
exchange: _brokerName,
|
||||||
|
routingKey: eventName);
|
||||||
|
|
||||||
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<IModel, IConnection>(channel, connection));
|
|
||||||
_handlers.Add(eventName, new List<IIntegrationEventHandler>());
|
_handlers.Add(eventName, new List<IIntegrationEventHandler>());
|
||||||
_handlers[eventName].Add(handler);
|
_handlers[eventName].Add(handler);
|
||||||
|
_eventTypes.Add(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -88,13 +79,69 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
|||||||
if (_handlers[eventName].Count == 0)
|
if (_handlers[eventName].Count == 0)
|
||||||
{
|
{
|
||||||
_handlers.Remove(eventName);
|
_handlers.Remove(eventName);
|
||||||
|
var eventType = _eventTypes.Single(e => e.Name == eventName);
|
||||||
|
_eventTypes.Remove(eventType);
|
||||||
|
_connection.Item1.QueueUnbind(queue: _queueName,
|
||||||
|
exchange: _brokerName,
|
||||||
|
routingKey: eventName);
|
||||||
|
|
||||||
var connectionItems =_listeners[eventName];
|
if (_handlers.Keys.Count == 0)
|
||||||
_listeners.Remove(eventName);
|
{
|
||||||
|
_queueName = string.Empty;
|
||||||
connectionItems.Item1.Close();
|
_connection.Item1.Close();
|
||||||
connectionItems.Item2.Close();
|
_connection.Item2.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IModel GetChannel()
|
||||||
|
{
|
||||||
|
if (_connection != null)
|
||||||
|
{
|
||||||
|
return _connection.Item1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var factory = new ConnectionFactory() { HostName = "172.20.0.1" };
|
||||||
|
var connection = factory.CreateConnection();
|
||||||
|
var channel = connection.CreateModel();
|
||||||
|
|
||||||
|
channel.ExchangeDeclare(exchange: _brokerName,
|
||||||
|
type: "direct");
|
||||||
|
if (string.IsNullOrEmpty(_queueName))
|
||||||
|
{
|
||||||
|
_queueName = channel.QueueDeclare().QueueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
var consumer = new EventingBasicConsumer(channel);
|
||||||
|
consumer.Received += (model, ea) =>
|
||||||
|
{
|
||||||
|
var eventName = ea.RoutingKey;
|
||||||
|
if (_handlers.ContainsKey(eventName))
|
||||||
|
{
|
||||||
|
var message = Encoding.UTF8.GetString(ea.Body);
|
||||||
|
Type eventType = _eventTypes.Single(t => t.Name == eventName);
|
||||||
|
|
||||||
|
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||||
|
var handlers = _handlers[eventName];
|
||||||
|
|
||||||
|
|
||||||
|
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||||
|
|
||||||
|
foreach (var handler in handlers)
|
||||||
|
{
|
||||||
|
concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
channel.BasicConsume(queue: _queueName,
|
||||||
|
noAck: true,
|
||||||
|
consumer: consumer);
|
||||||
|
_connection = new Tuple<IModel, IConnection>(channel, connection);
|
||||||
|
|
||||||
|
return _connection.Item1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,5 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
|||||||
{
|
{
|
||||||
public interface IIntegrationEvent
|
public interface IIntegrationEvent
|
||||||
{
|
{
|
||||||
string Name { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,7 @@ namespace Microsoft.eShopOnContainers.Services.Common.Infrastructure
|
|||||||
void Handle(TIntegrationEvent @event);
|
void Handle(TIntegrationEvent @event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IIntegrationEventHandler { }
|
public interface IIntegrationEventHandler
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<RootNamespace>Microsoft.eShopOnContainers.Services.Common.Infrastructure</RootNamespace>
|
<RootNamespace>Microsoft.eShopOnContainers.Services.Common.Infrastructure</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="4.1.1" />
|
<PackageReference Include="RabbitMQ.Client" Version="4.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user