diff --git a/CleanArchitecture.Domain/Constants/Messaging.cs b/CleanArchitecture.Domain/Constants/Messaging.cs new file mode 100644 index 0000000..8d2f401 --- /dev/null +++ b/CleanArchitecture.Domain/Constants/Messaging.cs @@ -0,0 +1,6 @@ +namespace CleanArchitecture.Domain.Constants; + +public sealed class Messaging +{ + public const string ExchangeNameNotifications = "exchange-notifications"; +} \ No newline at end of file diff --git a/CleanArchitecture.Domain/DomainEvents/DomainEvent.cs b/CleanArchitecture.Domain/DomainEvents/DomainEvent.cs index 37d8eaf..0219417 100644 --- a/CleanArchitecture.Domain/DomainEvents/DomainEvent.cs +++ b/CleanArchitecture.Domain/DomainEvents/DomainEvent.cs @@ -3,6 +3,7 @@ using MediatR; namespace CleanArchitecture.Domain.DomainEvents; +// Todo: Move this and all events to shared public abstract class DomainEvent : Message, INotification { public DateTime Timestamp { get; private set; } diff --git a/CleanArchitecture.Domain/EventHandler/Fanout/FanoutEventHandler.cs b/CleanArchitecture.Domain/EventHandler/Fanout/FanoutEventHandler.cs new file mode 100644 index 0000000..83e5a74 --- /dev/null +++ b/CleanArchitecture.Domain/EventHandler/Fanout/FanoutEventHandler.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using CleanArchitecture.Domain.Constants; +using CleanArchitecture.Domain.DomainEvents; +using CleanArchitecture.Domain.Rabbitmq; + +namespace CleanArchitecture.Domain.EventHandler.Fanout; + +public sealed class FanoutEventHandler : IFanoutEventHandler +{ + private readonly RabbitMqHandler _rabbitMqHandler; + + public FanoutEventHandler( + RabbitMqHandler rabbitMqHandler) + { + _rabbitMqHandler = rabbitMqHandler; + } + + public Task HandleDomainEventAsync(DomainEvent @event) + { + _rabbitMqHandler.EnqueueExchangeMessage( + Messaging.ExchangeNameNotifications, + @event); + + return Task.FromResult(@event); + } +} \ No newline at end of file diff --git a/CleanArchitecture.Domain/EventHandler/Fanout/IFanoutEventHandler.cs b/CleanArchitecture.Domain/EventHandler/Fanout/IFanoutEventHandler.cs new file mode 100644 index 0000000..c80cd3c --- /dev/null +++ b/CleanArchitecture.Domain/EventHandler/Fanout/IFanoutEventHandler.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using CleanArchitecture.Domain.DomainEvents; + +namespace CleanArchitecture.Domain.EventHandler.Fanout; + +public interface IFanoutEventHandler +{ + Task HandleDomainEventAsync(DomainEvent @event); +} \ No newline at end of file diff --git a/CleanArchitecture.Domain/Extensions/ServiceCollectionExtension.cs b/CleanArchitecture.Domain/Extensions/ServiceCollectionExtension.cs index eddd6e7..4195c2b 100644 --- a/CleanArchitecture.Domain/Extensions/ServiceCollectionExtension.cs +++ b/CleanArchitecture.Domain/Extensions/ServiceCollectionExtension.cs @@ -6,7 +6,9 @@ using CleanArchitecture.Domain.Commands.Users.CreateUser; using CleanArchitecture.Domain.Commands.Users.DeleteUser; using CleanArchitecture.Domain.Commands.Users.LoginUser; using CleanArchitecture.Domain.Commands.Users.UpdateUser; +using CleanArchitecture.Domain.DomainEvents; using CleanArchitecture.Domain.EventHandler; +using CleanArchitecture.Domain.EventHandler.Fanout; using CleanArchitecture.Domain.Events.Tenant; using CleanArchitecture.Domain.Events.User; using CleanArchitecture.Domain.Interfaces; @@ -36,6 +38,9 @@ public static class ServiceCollectionExtension public static IServiceCollection AddNotificationHandlers(this IServiceCollection services) { + // Fanout + services.AddScoped(); + // User services.AddScoped, UserEventHandler>(); services.AddScoped, UserEventHandler>(); diff --git a/CleanArchitecture.Infrastructure.Tests/InMemoryBusTests.cs b/CleanArchitecture.Infrastructure.Tests/InMemoryBusTests.cs index bd976e1..6f4795e 100644 --- a/CleanArchitecture.Infrastructure.Tests/InMemoryBusTests.cs +++ b/CleanArchitecture.Infrastructure.Tests/InMemoryBusTests.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using CleanArchitecture.Domain.Commands.Users.DeleteUser; using CleanArchitecture.Domain.DomainEvents; +using CleanArchitecture.Domain.EventHandler.Fanout; using CleanArchitecture.Domain.Events.User; using CleanArchitecture.Domain.Notifications; using MediatR; @@ -17,8 +18,9 @@ public sealed class InMemoryBusTests { var mediator = Substitute.For(); var domainEventStore = Substitute.For(); + var fanoutEventHandler = Substitute.For(); - var inMemoryBus = new InMemoryBus(mediator, domainEventStore); + var inMemoryBus = new InMemoryBus(mediator, domainEventStore, fanoutEventHandler); const string key = "Key"; const string value = "Value"; @@ -36,8 +38,9 @@ public sealed class InMemoryBusTests { var mediator = Substitute.For(); var domainEventStore = Substitute.For(); + var fanoutEventHandler = Substitute.For(); - var inMemoryBus = new InMemoryBus(mediator, domainEventStore); + var inMemoryBus = new InMemoryBus(mediator, domainEventStore, fanoutEventHandler); var userDeletedEvent = new UserDeletedEvent(Guid.NewGuid(), Guid.NewGuid()); @@ -51,8 +54,9 @@ public sealed class InMemoryBusTests { var mediator = Substitute.For(); var domainEventStore = Substitute.For(); + var fanoutEventHandler = Substitute.For(); - var inMemoryBus = new InMemoryBus(mediator, domainEventStore); + var inMemoryBus = new InMemoryBus(mediator, domainEventStore, fanoutEventHandler); var deleteUserCommand = new DeleteUserCommand(Guid.NewGuid()); diff --git a/CleanArchitecture.Infrastructure/InMemoryBus.cs b/CleanArchitecture.Infrastructure/InMemoryBus.cs index 703cbb2..660a4ec 100644 --- a/CleanArchitecture.Infrastructure/InMemoryBus.cs +++ b/CleanArchitecture.Infrastructure/InMemoryBus.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using CleanArchitecture.Domain.Commands; using CleanArchitecture.Domain.DomainEvents; +using CleanArchitecture.Domain.EventHandler.Fanout; using CleanArchitecture.Domain.Interfaces; using MediatR; @@ -10,13 +11,16 @@ public sealed class InMemoryBus : IMediatorHandler { private readonly IDomainEventStore _domainEventStore; private readonly IMediator _mediator; + private readonly IFanoutEventHandler _fanoutEventHandler; public InMemoryBus( IMediator mediator, - IDomainEventStore domainEventStore) + IDomainEventStore domainEventStore, + IFanoutEventHandler fanoutEventHandler) { _mediator = mediator; _domainEventStore = domainEventStore; + _fanoutEventHandler = fanoutEventHandler; } public Task QueryAsync(IRequest query) @@ -29,6 +33,8 @@ public sealed class InMemoryBus : IMediatorHandler await _domainEventStore.SaveAsync(@event); await _mediator.Publish(@event); + + await _fanoutEventHandler.HandleDomainEventAsync(@event); } public Task SendCommandAsync(T command) where T : CommandBase