Unverified Commit feea8d61 authored by Steve Smith's avatar Steve Smith Committed by GitHub

Converted domain events to async (#81)

parent 005493c9
using Ardalis.GuardClauses; using System.Threading.Tasks;
using Ardalis.GuardClauses;
using CleanArchitecture.Core.Events; using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Interfaces; using CleanArchitecture.Core.Interfaces;
...@@ -6,11 +7,13 @@ namespace CleanArchitecture.Core.Services ...@@ -6,11 +7,13 @@ namespace CleanArchitecture.Core.Services
{ {
public class ItemCompletedEmailNotificationHandler : IHandle<ToDoItemCompletedEvent> public class ItemCompletedEmailNotificationHandler : IHandle<ToDoItemCompletedEvent>
{ {
public void Handle(ToDoItemCompletedEvent domainEvent) public Task Handle(ToDoItemCompletedEvent domainEvent)
{ {
Guard.Against.Null(domainEvent, nameof(domainEvent)); Guard.Against.Null(domainEvent, nameof(domainEvent));
// Do Nothing // Do Nothing
return Task.CompletedTask;
} }
} }
} }
using CleanArchitecture.Core.SharedKernel; using System.Threading.Tasks;
using CleanArchitecture.Core.SharedKernel;
namespace CleanArchitecture.Core.Interfaces namespace CleanArchitecture.Core.Interfaces
{ {
public interface IDomainEventDispatcher public interface IDomainEventDispatcher
{ {
void Dispatch(BaseDomainEvent domainEvent); Task Dispatch(BaseDomainEvent domainEvent);
} }
} }
\ No newline at end of file
using CleanArchitecture.Core.SharedKernel; using System.Threading.Tasks;
using CleanArchitecture.Core.SharedKernel;
namespace CleanArchitecture.Core.Interfaces namespace CleanArchitecture.Core.Interfaces
{ {
public interface IHandle<T> where T : BaseDomainEvent public interface IHandle<in T> where T : BaseDomainEvent
{ {
void Handle(T domainEvent); Task Handle(T domainEvent);
} }
} }
\ No newline at end of file
using CleanArchitecture.Core.Interfaces; using CleanArchitecture.Core.Interfaces;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Linq; using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CleanArchitecture.Core.Entities; using CleanArchitecture.Core.Entities;
using CleanArchitecture.Core.SharedKernel; using CleanArchitecture.Core.SharedKernel;
using Ardalis.EFCore.Extensions; using Ardalis.EFCore.Extensions;
...@@ -35,9 +37,9 @@ namespace CleanArchitecture.Infrastructure.Data ...@@ -35,9 +37,9 @@ namespace CleanArchitecture.Infrastructure.Data
//modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); //modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
} }
public override int SaveChanges() public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
int result = base.SaveChanges(); int result = await base.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
// ignore events if no dispatcher provided // ignore events if no dispatcher provided
if (_dispatcher == null) return result; if (_dispatcher == null) return result;
...@@ -54,11 +56,16 @@ namespace CleanArchitecture.Infrastructure.Data ...@@ -54,11 +56,16 @@ namespace CleanArchitecture.Infrastructure.Data
entity.Events.Clear(); entity.Events.Clear();
foreach (var domainEvent in events) foreach (var domainEvent in events)
{ {
_dispatcher.Dispatch(domainEvent); await _dispatcher.Dispatch(domainEvent).ConfigureAwait(false);
} }
} }
return result; return result;
} }
public override int SaveChanges()
{
return SaveChangesAsync().GetAwaiter().GetResult();
}
} }
} }
\ No newline at end of file
...@@ -5,6 +5,7 @@ using System; ...@@ -5,6 +5,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace CleanArchitecture.Infrastructure.DomainEvents namespace CleanArchitecture.Infrastructure.DomainEvents
{ {
...@@ -19,7 +20,7 @@ namespace CleanArchitecture.Infrastructure.DomainEvents ...@@ -19,7 +20,7 @@ namespace CleanArchitecture.Infrastructure.DomainEvents
_container = container; _container = container;
} }
public void Dispatch(BaseDomainEvent domainEvent) public async Task Dispatch(BaseDomainEvent domainEvent)
{ {
Type handlerType = typeof(IHandle<>).MakeGenericType(domainEvent.GetType()); Type handlerType = typeof(IHandle<>).MakeGenericType(domainEvent.GetType());
Type wrapperType = typeof(DomainEventHandler<>).MakeGenericType(domainEvent.GetType()); Type wrapperType = typeof(DomainEventHandler<>).MakeGenericType(domainEvent.GetType());
...@@ -29,13 +30,13 @@ namespace CleanArchitecture.Infrastructure.DomainEvents ...@@ -29,13 +30,13 @@ namespace CleanArchitecture.Infrastructure.DomainEvents
foreach (DomainEventHandler handler in wrappedHandlers) foreach (DomainEventHandler handler in wrappedHandlers)
{ {
handler.Handle(domainEvent); await handler.Handle(domainEvent).ConfigureAwait(false);
} }
} }
private abstract class DomainEventHandler private abstract class DomainEventHandler
{ {
public abstract void Handle(BaseDomainEvent domainEvent); public abstract Task Handle(BaseDomainEvent domainEvent);
} }
private class DomainEventHandler<T> : DomainEventHandler private class DomainEventHandler<T> : DomainEventHandler
...@@ -48,9 +49,9 @@ namespace CleanArchitecture.Infrastructure.DomainEvents ...@@ -48,9 +49,9 @@ namespace CleanArchitecture.Infrastructure.DomainEvents
_handler = handler; _handler = handler;
} }
public override void Handle(BaseDomainEvent domainEvent) public override Task Handle(BaseDomainEvent domainEvent)
{ {
_handler.Handle((T)domainEvent); return _handler.Handle((T)domainEvent);
} }
} }
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using CleanArchitecture.Core.Events; using CleanArchitecture.Core.Events;
using CleanArchitecture.Core.Services; using CleanArchitecture.Core.Services;
using System; using System;
using System.Threading.Tasks;
using Xunit; using Xunit;
namespace CleanArchitecture.UnitTests.Core.Entities namespace CleanArchitecture.UnitTests.Core.Entities
...@@ -9,19 +10,19 @@ namespace CleanArchitecture.UnitTests.Core.Entities ...@@ -9,19 +10,19 @@ namespace CleanArchitecture.UnitTests.Core.Entities
public class ItemCompletedEmailNotificationHandlerHandle public class ItemCompletedEmailNotificationHandlerHandle
{ {
[Fact] [Fact]
public void ThrowsExceptionGivenNullEventArgument() public async Task ThrowsExceptionGivenNullEventArgument()
{ {
var handler = new ItemCompletedEmailNotificationHandler(); var handler = new ItemCompletedEmailNotificationHandler();
Exception ex = Assert.Throws<ArgumentNullException>(() => handler.Handle(null)); Exception ex = await Assert.ThrowsAsync<ArgumentNullException>(() => handler.Handle(null));
} }
[Fact] [Fact]
public void DoesNothingGivenEventInstance() public async Task DoesNothingGivenEventInstance()
{ {
var handler = new ItemCompletedEmailNotificationHandler(); var handler = new ItemCompletedEmailNotificationHandler();
handler.Handle(new ToDoItemCompletedEvent(new ToDoItem())); await handler.Handle(new ToDoItemCompletedEvent(new ToDoItem()));
} }
} }
} }
using CleanArchitecture.Core.Interfaces; using System.Threading.Tasks;
using CleanArchitecture.Core.Interfaces;
using CleanArchitecture.Core.SharedKernel; using CleanArchitecture.Core.SharedKernel;
namespace CleanArchitecture.UnitTests namespace CleanArchitecture.UnitTests
{ {
public class NoOpDomainEventDispatcher : IDomainEventDispatcher public class NoOpDomainEventDispatcher : IDomainEventDispatcher
{ {
public void Dispatch(BaseDomainEvent domainEvent) { } public Task Dispatch(BaseDomainEvent domainEvent)
{
return Task.CompletedTask;
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment