Skip to content

Commit f297f8b

Browse files
committed
Refactor to event bus to support dynamic subscriptions to events
Checkout HTTP entrypoint in Basket API
1 parent 755d180 commit f297f8b

18 files changed

Lines changed: 347 additions & 75 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions
8+
{
9+
public interface IDynamicIntegrationEventHandler
10+
{
11+
Task Handle(dynamic eventData);
12+
}
13+
}

src/BuildingBlocks/EventBus/EventBus/Abstractions/IEventBus.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ public interface IEventBus
88
void Subscribe<T, TH>(Func<TH> handler)
99
where T : IntegrationEvent
1010
where TH : IIntegrationEventHandler<T>;
11+
void SubscribeDynamic<TH>(string eventName, Func<TH> handler)
12+
where TH : IDynamicIntegrationEventHandler;
13+
14+
void UnsubscribeDynamic<TH>(string eventName)
15+
where TH : IDynamicIntegrationEventHandler;
16+
1117
void Unsubscribe<T, TH>()
1218
where TH : IIntegrationEventHandler<T>
1319
where T : IntegrationEvent;

src/BuildingBlocks/EventBus/EventBus/EventBus.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.EventBus</RootNamespace>
77
</PropertyGroup>
88

9-
<ItemGroup>
10-
<Folder Include="Abstractions\" />
11-
</ItemGroup>
12-
139
<ItemGroup>
1410
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
1511
</ItemGroup>

src/BuildingBlocks/EventBus/EventBus/IEventBusSubscriptionsManager.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,33 @@
22
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
33
using System;
44
using System.Collections.Generic;
5+
using static Microsoft.eShopOnContainers.BuildingBlocks.EventBus.InMemoryEventBusSubscriptionsManager;
56

67
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
78
{
89
public interface IEventBusSubscriptionsManager
910
{
1011
bool IsEmpty { get; }
1112
event EventHandler<string> OnEventRemoved;
13+
void AddDynamicSubscription<TH>(string eventName, Func<TH> handler)
14+
where TH : IDynamicIntegrationEventHandler;
15+
1216
void AddSubscription<T, TH>(Func<TH> handler)
1317
where T : IntegrationEvent
1418
where TH : IIntegrationEventHandler<T>;
1519

16-
void RemoveSubscription<T, TH>()
17-
where TH : IIntegrationEventHandler<T>
18-
where T : IntegrationEvent;
20+
void RemoveSubscription<T, TH>()
21+
where TH : IIntegrationEventHandler<T>
22+
where T : IntegrationEvent;
23+
void RemoveDynamicSubscription<TH>(string eventName)
24+
where TH : IDynamicIntegrationEventHandler;
25+
1926
bool HasSubscriptionsForEvent<T>() where T : IntegrationEvent;
2027
bool HasSubscriptionsForEvent(string eventName);
2128
Type GetEventTypeByName(string eventName);
2229
void Clear();
23-
IEnumerable<Delegate> GetHandlersForEvent<T>() where T : IntegrationEvent;
24-
IEnumerable<Delegate> GetHandlersForEvent(string eventName);
30+
IEnumerable<SubscriptionInfo> GetHandlersForEvent<T>() where T : IntegrationEvent;
31+
IEnumerable<SubscriptionInfo> GetHandlersForEvent(string eventName);
32+
string GetEventKey<T>();
2533
}
2634
}

src/BuildingBlocks/EventBus/EventBus/InMemoryEventBusSubscriptionsManager.cs

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,99 @@
88

99
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
1010
{
11-
public class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
11+
public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
1212
{
13-
private readonly Dictionary<string, List<Delegate>> _handlers;
13+
14+
15+
private readonly Dictionary<string, List<SubscriptionInfo>> _handlers;
1416
private readonly List<Type> _eventTypes;
1517

1618
public event EventHandler<string> OnEventRemoved;
1719

1820
public InMemoryEventBusSubscriptionsManager()
1921
{
20-
_handlers = new Dictionary<string, List<Delegate>>();
22+
_handlers = new Dictionary<string, List<SubscriptionInfo>>();
2123
_eventTypes = new List<Type>();
2224
}
2325

2426
public bool IsEmpty => !_handlers.Keys.Any();
2527
public void Clear() => _handlers.Clear();
2628

27-
public void AddSubscription<T, TH>(Func<TH> handler)
29+
public void AddDynamicSubscription<TH>(string eventName, Func<TH> handler)
30+
where TH : IDynamicIntegrationEventHandler
31+
{
32+
DoAddSubscription(handler, eventName, isDynamic: true);
33+
}
34+
35+
public void AddSubscription<T, TH>(Func<TH> handler)
2836
where T : IntegrationEvent
2937
where TH : IIntegrationEventHandler<T>
3038
{
31-
var key = GetEventKey<T>();
32-
if (!HasSubscriptionsForEvent<T>())
39+
var eventName = GetEventKey<T>();
40+
DoAddSubscription(handler, eventName, isDynamic: false);
41+
_eventTypes.Add(typeof(T));
42+
}
43+
44+
private void DoAddSubscription(Delegate handler, string eventName, bool isDynamic)
45+
{
46+
if (!HasSubscriptionsForEvent(eventName))
3347
{
34-
_handlers.Add(key, new List<Delegate>());
48+
_handlers.Add(eventName, new List<SubscriptionInfo>());
3549
}
36-
_handlers[key].Add(handler);
37-
_eventTypes.Add(typeof(T));
50+
if (isDynamic)
51+
{
52+
_handlers[eventName].Add(SubscriptionInfo.Dynamic(handler));
53+
}
54+
else
55+
{
56+
_handlers[eventName].Add(SubscriptionInfo.Typed(handler));
57+
}
58+
}
59+
60+
61+
public void RemoveDynamicSubscription<TH>(string eventName)
62+
where TH : IDynamicIntegrationEventHandler
63+
{
64+
var handlerToRemove = FindDynamicSubscriptionToRemove<TH>(eventName);
65+
DoRemoveHandler(eventName, handlerToRemove);
3866
}
3967

68+
4069
public void RemoveSubscription<T, TH>()
4170
where TH : IIntegrationEventHandler<T>
4271
where T : IntegrationEvent
4372
{
44-
var handlerToRemove = FindHandlerToRemove<T, TH>();
45-
if (handlerToRemove != null)
73+
var handlerToRemove = FindSubscriptionToRemove<T, TH>();
74+
var eventName = GetEventKey<T>();
75+
DoRemoveHandler(eventName, handlerToRemove);
76+
}
77+
78+
79+
private void DoRemoveHandler(string eventName, SubscriptionInfo subsToRemove)
80+
{
81+
if (subsToRemove != null)
4682
{
47-
var key = GetEventKey<T>();
48-
_handlers[key].Remove(handlerToRemove);
49-
if (!_handlers[key].Any())
83+
_handlers[eventName].Remove(subsToRemove);
84+
if (!_handlers[eventName].Any())
5085
{
51-
_handlers.Remove(key);
52-
var eventType = _eventTypes.SingleOrDefault(e => e.Name == key);
86+
_handlers.Remove(eventName);
87+
var eventType = _eventTypes.SingleOrDefault(e => e.Name == eventName);
5388
if (eventType != null)
5489
{
5590
_eventTypes.Remove(eventType);
56-
RaiseOnEventRemoved(eventType.Name);
5791
}
92+
RaiseOnEventRemoved(eventName);
5893
}
59-
94+
6095
}
6196
}
6297

63-
public IEnumerable<Delegate> GetHandlersForEvent<T>() where T : IntegrationEvent
98+
public IEnumerable<SubscriptionInfo> GetHandlersForEvent<T>() where T : IntegrationEvent
6499
{
65100
var key = GetEventKey<T>();
66101
return GetHandlersForEvent(key);
67102
}
68-
public IEnumerable<Delegate> GetHandlersForEvent(string eventName) => _handlers[eventName];
103+
public IEnumerable<SubscriptionInfo> GetHandlersForEvent(string eventName) => _handlers[eventName];
69104

70105
private void RaiseOnEventRemoved(string eventName)
71106
{
@@ -76,22 +111,34 @@ private void RaiseOnEventRemoved(string eventName)
76111
}
77112
}
78113

79-
private Delegate FindHandlerToRemove<T, TH>()
80-
where T : IntegrationEvent
81-
where TH : IIntegrationEventHandler<T>
114+
115+
private SubscriptionInfo FindDynamicSubscriptionToRemove<TH>(string eventName)
116+
where TH : IDynamicIntegrationEventHandler
82117
{
83-
if (!HasSubscriptionsForEvent<T>())
118+
return DoFindHandlerToRemove(eventName, typeof(TH));
119+
}
120+
121+
122+
private SubscriptionInfo FindSubscriptionToRemove<T, TH>()
123+
where T : IntegrationEvent
124+
where TH : IIntegrationEventHandler<T>
125+
{
126+
var eventName = GetEventKey<T>();
127+
return DoFindHandlerToRemove(eventName, typeof(TH));
128+
}
129+
130+
private SubscriptionInfo DoFindHandlerToRemove(string eventName, Type handlerType)
131+
{
132+
if (!HasSubscriptionsForEvent(eventName))
84133
{
85134
return null;
86135
}
87-
88-
var key = GetEventKey<T>();
89-
foreach (var func in _handlers[key])
136+
foreach (var subscription in _handlers[eventName])
90137
{
91-
var genericArgs = func.GetType().GetGenericArguments();
92-
if (genericArgs.SingleOrDefault() == typeof(TH))
138+
var genericArgs = subscription.Factory.GetType().GetGenericArguments();
139+
if (genericArgs.SingleOrDefault() == handlerType)
93140
{
94-
return func;
141+
return subscription;
95142
}
96143
}
97144

@@ -104,10 +151,10 @@ public bool HasSubscriptionsForEvent<T>() where T : IntegrationEvent
104151
return HasSubscriptionsForEvent(key);
105152
}
106153
public bool HasSubscriptionsForEvent(string eventName) => _handlers.ContainsKey(eventName);
107-
108-
public Type GetEventTypeByName(string eventName) => _eventTypes.Single(t => t.Name == eventName);
109154

110-
private string GetEventKey<T>()
155+
public Type GetEventTypeByName(string eventName) => _eventTypes.SingleOrDefault(t => t.Name == eventName);
156+
157+
public string GetEventKey<T>()
111158
{
112159
return typeof(T).Name;
113160
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
3+
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus
4+
{
5+
public partial class InMemoryEventBusSubscriptionsManager : IEventBusSubscriptionsManager
6+
{
7+
public class SubscriptionInfo
8+
{
9+
public bool IsDynamic { get; }
10+
public Delegate Factory { get; }
11+
12+
private SubscriptionInfo(bool isDynamic, Delegate factory)
13+
{
14+
IsDynamic = isDynamic;
15+
Factory = factory;
16+
}
17+
18+
public static SubscriptionInfo Dynamic(Delegate factory)
19+
{
20+
return new SubscriptionInfo(true, factory);
21+
}
22+
public static SubscriptionInfo Typed(Delegate factory)
23+
{
24+
return new SubscriptionInfo(false, factory);
25+
}
26+
}
27+
}
28+
}

src/BuildingBlocks/EventBus/EventBusRabbitMQ/CommandBusRabbitMQ.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.eShopOnContainers.BuildingBlocks.CommandBus;
1+
//using Microsoft.eShopOnContainers.BuildingBlocks.CommandBus;
22
using Microsoft.Extensions.Logging;
33
using Newtonsoft.Json;
44
using Polly;
@@ -12,6 +12,7 @@
1212
using System.Text;
1313
using System.Threading.Tasks;
1414

15+
/*
1516
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
1617
{
1718
public class CommandBusRabbitMQ : ICommandBus, IDisposable
@@ -141,3 +142,4 @@ public void Dispose()
141142
142143
}
143144
}
145+
*/

0 commit comments

Comments
 (0)