using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
public static void Main()
var client = new InMemoryEventBusClient(new ServiceCollection().BuildServiceProvider());
client.Subscribe<TestEvent, TestHandler>();
client.PublishAsync(new TestEvent());
class TestEvent : IIntegrationEvent;
internal class TestHandler : IIntegrationEventHandler<TestEvent>
public async Task HandleAsync(TestEvent @event, CancellationToken cancellationToken = default)
Console.WriteLine("Handled");
public interface IIntegrationEvent;
public interface IIntegrationEventHandler;
public interface IIntegrationEventHandler<in T> : IIntegrationEventHandler where T : IIntegrationEvent
Task HandleAsync(T @event, CancellationToken cancellationToken = default);
public interface IEventBus
Task PublishAsync<T>(T @event, CancellationToken cancellationToken = default) where T : IIntegrationEvent;
void Subscribe<T, THandler>() where T : IIntegrationEvent where THandler : IIntegrationEventHandler<T>;
public sealed class InMemoryEventBusClient : IEventBus
private readonly IServiceProvider _serviceProvider;
public InMemoryEventBusClient(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
public async Task PublishAsync<T>(T @event, CancellationToken cancellationToken = default) where T : IIntegrationEvent
await InMemoryEventBus.Instance.PublishAsync(@event, cancellationToken);
public void Subscribe<T, THandler>() where T : IIntegrationEvent where THandler : IIntegrationEventHandler<T>
var handler = ActivatorUtilities.CreateInstance<THandler>(_serviceProvider);
InMemoryEventBus.Instance.Subscribe(handler);
public sealed class InMemoryEventBus
public static InMemoryEventBus Instance { get; } = new();
private readonly Dictionary<string, List<IIntegrationEventHandler>> _handlersDictionary = new Dictionary<string, List<IIntegrationEventHandler>>();
public async Task PublishAsync<T>(T @event, CancellationToken cancellationToken = default) where T : IIntegrationEvent
var eventType = @event.GetType().FullName;
foreach (var integrationEventHandler in _handlersDictionary[eventType])
if (integrationEventHandler is IIntegrationEventHandler<T> handler)
await handler.HandleAsync(@event, cancellationToken);
public void Subscribe<T>(IIntegrationEventHandler<T> handler) where T : IIntegrationEvent
var eventType = typeof(T).FullName;
if (!_handlersDictionary.TryGetValue(eventType, out var handlers))
_handlersDictionary.Add(eventType, [handler]);
else handlers.Add(handler);