Skip to content

Commit

Permalink
Merge Domain Event Dispatcher with Command and Query Dispatcher
Browse files Browse the repository at this point in the history
  • Loading branch information
phongnguyend committed Jun 27, 2023
1 parent 0be8194 commit 6d62e34
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using ClassifiedAds.Application.SmsMessages.Services;
using ClassifiedAds.Application.Users.Services;
using ClassifiedAds.Domain.Entities;
using ClassifiedAds.Domain.Events;
using System;
using System.Linq;
using System.Reflection;
Expand All @@ -16,11 +15,7 @@ public static class ApplicationServicesExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services, Action<Type, Type, ServiceLifetime> configureInterceptor = null)
{
DomainEvents.RegisterHandlers(Assembly.GetExecutingAssembly(), services);

services
.AddScoped<IDomainEvents, DomainEvents>()
.AddScoped(typeof(ICrudService<>), typeof(CrudService<>))
services.AddScoped(typeof(ICrudService<>), typeof(CrudService<>))
.AddScoped<IUserService, UserService>()
.AddScoped<IProductService, ProductService>()
.AddScoped<EmailMessageService>()
Expand All @@ -46,7 +41,9 @@ public static IServiceCollection AddMessageHandlers(this IServiceCollection serv
{
services.AddScoped<Dispatcher>();

var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
var assembly = Assembly.GetExecutingAssembly();

var assemblyTypes = assembly.GetTypes();

foreach (var type in assemblyTypes)
{
Expand Down Expand Up @@ -91,6 +88,8 @@ public static IServiceCollection AddMessageHandlers(this IServiceCollection serv
}
}

Dispatcher.RegisterEventHandlers(assembly, services);

return services;
}
}
40 changes: 39 additions & 1 deletion src/Monolith/ClassifiedAds.Application/Common/Dispatcher.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
using System;
using ClassifiedAds.Domain.Events;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -8,6 +13,22 @@ public class Dispatcher
{
private readonly IServiceProvider _provider;

private static List<Type> _eventHandlers = new List<Type>();

public static void RegisterEventHandlers(Assembly assembly, IServiceCollection services)
{
var types = assembly.GetTypes()
.Where(x => x.GetInterfaces().Any(y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IDomainEventHandler<>)))
.ToList();

foreach (var type in types)
{
services.AddTransient(type);
}

_eventHandlers.AddRange(types);
}

public Dispatcher(IServiceProvider provider)
{
_provider = provider;
Expand All @@ -34,4 +55,21 @@ public async Task<T> DispatchAsync<T>(IQuery<T> query, CancellationToken cancell

return await result;
}

public async Task DispatchAsync(IDomainEvent domainEvent, CancellationToken cancellationToken = default)
{
foreach (Type handlerType in _eventHandlers)
{
bool canHandleEvent = handlerType.GetInterfaces()
.Any(x => x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IDomainEventHandler<>)
&& x.GenericTypeArguments[0] == domainEvent.GetType());

if (canHandleEvent)
{
dynamic handler = _provider.GetService(handlerType);
await handler.HandleAsync((dynamic)domainEvent, cancellationToken);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public class CrudService<T> : ICrudService<T>
{
private readonly IUnitOfWork _unitOfWork;
protected readonly IRepository<T, Guid> _repository;
private readonly IDomainEvents _domainEvents;
protected readonly Dispatcher _dispatcher;

public CrudService(IRepository<T, Guid> repository, IDomainEvents domainEvents)
public CrudService(IRepository<T, Guid> repository, Dispatcher dispatcher)
{
_unitOfWork = repository.UnitOfWork;
_repository = repository;
_domainEvents = domainEvents;
_dispatcher = dispatcher;
}

public Task<List<T>> GetAsync(CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -51,20 +51,20 @@ public async Task AddAsync(T entity, CancellationToken cancellationToken = defau
{
await _repository.AddAsync(entity, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _domainEvents.DispatchAsync(new EntityCreatedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
await _dispatcher.DispatchAsync(new EntityCreatedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
}

public async Task UpdateAsync(T entity, CancellationToken cancellationToken = default)
{
await _repository.UpdateAsync(entity, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _domainEvents.DispatchAsync(new EntityUpdatedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
await _dispatcher.DispatchAsync(new EntityUpdatedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
}

public async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
{
_repository.Delete(entity);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _domainEvents.DispatchAsync(new EntityDeletedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
await _dispatcher.DispatchAsync(new EntityDeletedEvent<T>(entity, DateTime.UtcNow), cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ClassifiedAds.Domain.Entities;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Identity;
using ClassifiedAds.Domain.Repositories;
using System;
Expand All @@ -8,8 +7,8 @@ namespace ClassifiedAds.Application.Products.Services;

public class ProductService : CrudService<Product>, IProductService
{
public ProductService(IRepository<Product, Guid> productRepository, IDomainEvents domainEvents, ICurrentUser currentUser)
: base(productRepository, domainEvents)
public ProductService(IRepository<Product, Guid> productRepository, Dispatcher dispatcher, ICurrentUser currentUser)
: base(productRepository, dispatcher)
{
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using ClassifiedAds.Domain.Entities;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Repositories;
using System;

namespace ClassifiedAds.Application.Users.Services;

public class UserService : CrudService<User>, IUserService
{
public UserService(IRepository<User, Guid> userRepository, IDomainEvents domainEvents)
: base(userRepository, domainEvents)
public UserService(IRepository<User, Guid> userRepository, Dispatcher dispatcher)
: base(userRepository, dispatcher)
{
}
}
3 changes: 2 additions & 1 deletion src/Monolith/ClassifiedAds.BackgroundServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public static void Main(string[] args)
services.AddDateTimeProvider();
services.AddPersistence(appSettings.ConnectionStrings.ClassifiedAds)
.AddDomainServices()
.AddApplicationServices();
.AddApplicationServices()
.AddMessageHandlers();
services.AddMessageBusSender<FileUploadedEvent>(appSettings.MessageBroker);
services.AddMessageBusSender<FileDeletedEvent>(appSettings.MessageBroker);
Expand Down
51 changes: 0 additions & 51 deletions src/Monolith/ClassifiedAds.Domain/Events/DomainEvents.cs

This file was deleted.

9 changes: 0 additions & 9 deletions src/Monolith/ClassifiedAds.Domain/Events/IDomainEvents.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using ClassifiedAds.Application;
using ClassifiedAds.Application.Users.Services;
using ClassifiedAds.CrossCuttingConcerns.Exceptions;
using ClassifiedAds.Domain.Entities;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Repositories;
using Moq;
using System;
Expand All @@ -20,8 +20,9 @@ public class UserServiceTests
public UserServiceTests()
{
_userRepository = new Mock<IRepository<User, Guid>>();
var domainEvents = new Mock<IDomainEvents>();
_userService = new UserService(_userRepository.Object, domainEvents.Object);
var serviceProvider = new Mock<IServiceProvider>();
var dispatcher = new Dispatcher(serviceProvider.Object);
_userService = new UserService(_userRepository.Object, dispatcher);
}

[Fact]
Expand Down

0 comments on commit 6d62e34

Please sign in to comment.