Browse Source

Remove sync API from IEventBus.

pull/279/head
Halil İbrahim Kalkan 8 years ago
parent
commit
c3d59e76b0
  1. 84
      src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs
  2. 26
      src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs
  3. 41
      src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs
  4. 3
      src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  5. 37
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs
  6. 167
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBus.cs
  7. 65
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs
  8. 15
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandler.cs
  9. 8
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerFactory.cs
  10. 5
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/IocEventHandlerFactory.cs
  11. 34
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/NullEventBus.cs
  12. 8
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/SingleInstanceHandlerFactory.cs
  13. 5
      src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs
  14. 56
      src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs
  15. 7
      src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs
  16. 5
      src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs
  17. 29
      src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs
  18. 50
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/ActionBasedEventHandlerTest.cs
  19. 4
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_DI_Services_Test.cs
  20. 16
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_Exception_Test.cs
  21. 20
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_MultipleHandle_Test.cs
  22. 12
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/GenericInheritanceTest.cs
  23. 23
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/InheritanceTest.cs
  24. 8
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventDataHandler.cs
  25. 6
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleTransientEventHandler.cs
  26. 9
      test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/TransientDisposableEventHandlerTest.cs
  27. 3
      test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs
  28. 8
      test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs
  29. 10
      test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

84
src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs

@ -23,98 +23,86 @@ namespace Volo.Abp.Domain.Entities.Events
EventBus = NullEventBus.Instance; EventBus = NullEventBus.Instance;
} }
public virtual void TriggerEvents(EntityChangeReport changeReport) public async Task TriggerEventsAsync(EntityChangeReport changeReport)
{ {
TriggerEventsInternal(changeReport); await TriggerEventsInternalAsync(changeReport);
if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null) if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null)
{ {
return; return;
} }
_unitOfWorkManager.Current.SaveChanges(); await _unitOfWorkManager.Current.SaveChangesAsync();
} }
public Task TriggerEventsAsync(EntityChangeReport changeReport) //TODO: Trigger events really async! public virtual async Task TriggerEntityCreatingEventAsync(object entity)
{ {
TriggerEventsInternal(changeReport); await TriggerEventWithEntity(typeof(EntityCreatingEventData<>), entity, true);
if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null)
{
return Task.FromResult(0);
}
return _unitOfWorkManager.Current.SaveChangesAsync();
}
public virtual void TriggerEntityCreatingEvent(object entity)
{
TriggerEventWithEntity(typeof(EntityCreatingEventData<>), entity, true);
} }
public void TriggerEntityCreatedEvent(object entity) public async Task TriggerEntityCreatedEventAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, true); await TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, true);
} }
public virtual void TriggerEntityCreatedEventOnUowCompleted(object entity) public virtual async Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, false); await TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, false);
} }
public virtual void TriggerEntityUpdatingEvent(object entity) public virtual async Task TriggerEntityUpdatingEventAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityUpdatingEventData<>), entity, true); await TriggerEventWithEntity(typeof(EntityUpdatingEventData<>), entity, true);
} }
public void TriggerEntityUpdatedEvent(object entity) public async Task TriggerEntityUpdatedEventAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, true); await TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, true);
} }
public virtual void TriggerEntityUpdatedEventOnUowCompleted(object entity) public virtual async Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, false); await TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, false);
} }
public virtual void TriggerEntityDeletingEvent(object entity) public virtual async Task TriggerEntityDeletingEventAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityDeletingEventData<>), entity, true); await TriggerEventWithEntity(typeof(EntityDeletingEventData<>), entity, true);
} }
public void TriggerEntityDeletedEvent(object entity) public async Task TriggerEntityDeletedEventAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, true); await TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, true);
} }
public virtual void TriggerEntityDeletedEventOnUowCompleted(object entity) public virtual async Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity)
{ {
TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, false); await TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, false);
} }
public virtual void TriggerEventsInternal(EntityChangeReport changeReport) protected virtual async Task TriggerEventsInternalAsync(EntityChangeReport changeReport)
{ {
TriggerEntityChangeEvents(changeReport.ChangedEntities); await TriggerEntityChangeEvents(changeReport.ChangedEntities);
TriggerDomainEvents(changeReport.DomainEvents); await TriggerDomainEvents(changeReport.DomainEvents);
} }
protected virtual void TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities) protected virtual async Task TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities)
{ {
foreach (var changedEntity in changedEntities) foreach (var changedEntity in changedEntities)
{ {
switch (changedEntity.ChangeType) switch (changedEntity.ChangeType)
{ {
case EntityChangeType.Created: case EntityChangeType.Created:
TriggerEntityCreatingEvent(changedEntity.Entity); await TriggerEntityCreatingEventAsync(changedEntity.Entity);
TriggerEntityCreatedEventOnUowCompleted(changedEntity.Entity); await TriggerEntityCreatedEventOnUowCompletedAsync(changedEntity.Entity);
break; break;
case EntityChangeType.Updated: case EntityChangeType.Updated:
TriggerEntityUpdatingEvent(changedEntity.Entity); await TriggerEntityUpdatingEventAsync(changedEntity.Entity);
TriggerEntityUpdatedEventOnUowCompleted(changedEntity.Entity); await TriggerEntityUpdatedEventOnUowCompletedAsync(changedEntity.Entity);
break; break;
case EntityChangeType.Deleted: case EntityChangeType.Deleted:
TriggerEntityDeletingEvent(changedEntity.Entity); await TriggerEntityDeletingEventAsync(changedEntity.Entity);
TriggerEntityDeletedEventOnUowCompleted(changedEntity.Entity); await TriggerEntityDeletedEventOnUowCompletedAsync(changedEntity.Entity);
break; break;
default: default:
throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType); throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType);
@ -122,26 +110,26 @@ namespace Volo.Abp.Domain.Entities.Events
} }
} }
protected virtual void TriggerDomainEvents(List<DomainEventEntry> domainEvents) protected virtual async Task TriggerDomainEvents(List<DomainEventEntry> domainEvents)
{ {
foreach (var domainEvent in domainEvents) foreach (var domainEvent in domainEvents)
{ {
EventBus.Trigger(domainEvent.EventData.GetType(), domainEvent.EventData); await EventBus.TriggerAsync(domainEvent.EventData.GetType(), domainEvent.EventData);
} }
} }
protected virtual void TriggerEventWithEntity(Type genericEventType, object entity, bool triggerInCurrentUnitOfWork) protected virtual async Task TriggerEventWithEntity(Type genericEventType, object entity, bool triggerInCurrentUnitOfWork)
{ {
var entityType = ProxyHelper.UnProxy(entity).GetType(); var entityType = ProxyHelper.UnProxy(entity).GetType();
var eventType = genericEventType.MakeGenericType(entityType); var eventType = genericEventType.MakeGenericType(entityType);
if (triggerInCurrentUnitOfWork || _unitOfWorkManager.Current == null) if (triggerInCurrentUnitOfWork || _unitOfWorkManager.Current == null)
{ {
EventBus.Trigger(eventType, Activator.CreateInstance(eventType, entity)); await EventBus.TriggerAsync(eventType, Activator.CreateInstance(eventType, entity));
return; return;
} }
_unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, Activator.CreateInstance(eventType, entity)); _unitOfWorkManager.Current.OnCompleted(() => EventBus.TriggerAsync(eventType, Activator.CreateInstance(eventType, entity)));
} }
} }
} }

26
src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs

@ -7,26 +7,18 @@ namespace Volo.Abp.Domain.Entities.Events
/// </summary> /// </summary>
public interface IEntityChangeEventHelper public interface IEntityChangeEventHelper
{ {
void TriggerEvents(EntityChangeReport changeReport);
Task TriggerEventsAsync(EntityChangeReport changeReport); Task TriggerEventsAsync(EntityChangeReport changeReport);
void TriggerEntityCreatingEvent(object entity); Task TriggerEntityCreatingEventAsync(object entity);
Task TriggerEntityCreatedEventAsync(object entity);
void TriggerEntityCreatedEvent(object entity); Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity);
void TriggerEntityCreatedEventOnUowCompleted(object entity);
void TriggerEntityUpdatingEvent(object entity);
void TriggerEntityUpdatedEvent(object entity);
void TriggerEntityUpdatedEventOnUowCompleted(object entity);
void TriggerEntityDeletingEvent(object entity); Task TriggerEntityUpdatingEventAsync(object entity);
Task TriggerEntityUpdatedEventAsync(object entity);
Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity);
void TriggerEntityDeletedEvent(object entity); Task TriggerEntityDeletingEventAsync(object entity);
Task TriggerEntityDeletedEventAsync(object entity);
void TriggerEntityDeletedEventOnUowCompleted(object entity); Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity);
} }
} }

41
src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs

@ -17,54 +17,49 @@ namespace Volo.Abp.Domain.Entities.Events
} }
public void TriggerEntityCreatingEvent(object entity) public Task TriggerEntityCreatingEventAsync(object entity)
{ {
return Task.CompletedTask;
}
public void TriggerEntityCreatedEvent(object entity)
{
} }
public void TriggerEntityCreatedEventOnUowCompleted(object entity) public Task TriggerEntityCreatedEventAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityUpdatingEvent(object entity) public Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityUpdatedEvent(object entity) public Task TriggerEntityUpdatingEventAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityUpdatedEventOnUowCompleted(object entity) public Task TriggerEntityUpdatedEventAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityDeletingEvent(object entity) public Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityDeletedEvent(object entity) public Task TriggerEntityDeletingEventAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEntityDeletedEventOnUowCompleted(object entity) public Task TriggerEntityDeletedEventAsync(object entity)
{ {
return Task.CompletedTask;
} }
public void TriggerEvents(EntityChangeReport changeReport) public Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity)
{ {
return Task.CompletedTask;
} }
public Task TriggerEventsAsync(EntityChangeReport changeReport) public Task TriggerEventsAsync(EntityChangeReport changeReport)

3
src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

@ -17,6 +17,7 @@ using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection; using Volo.Abp.Reflection;
using Volo.Abp.Threading;
namespace Volo.Abp.EntityFrameworkCore namespace Volo.Abp.EntityFrameworkCore
{ {
@ -76,7 +77,7 @@ namespace Volo.Abp.EntityFrameworkCore
ChangeTracker.AutoDetectChangesEnabled = false; //TODO: Why this is needed? ChangeTracker.AutoDetectChangesEnabled = false; //TODO: Why this is needed?
var changeReport = ApplyAbpConcepts(); var changeReport = ApplyAbpConcepts();
var result = base.SaveChanges(acceptAllChangesOnSuccess); var result = base.SaveChanges(acceptAllChangesOnSuccess);
EntityChangeEventHelper.TriggerEvents(changeReport); AsyncHelper.RunSync(() => EntityChangeEventHelper.TriggerEventsAsync(changeReport));
return result; return result;
} }
catch (DbUpdateConcurrencyException ex) catch (DbUpdateConcurrencyException ex)

37
src/Volo.Abp.EventBus/Volo/Abp/EventBus/ActionEventHandler.cs

@ -1,37 +0,0 @@
using System;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.EventBus
{
/// <summary>
/// This event handler is an adapter to be able to use an action as <see cref="IEventHandler{TEventData}"/> implementation.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
internal class ActionEventHandler<TEvent> :
IEventHandler<TEvent>,
ITransientDependency
{
/// <summary>
/// Action to handle the event.
/// </summary>
public Action<TEvent> Action { get; private set; }
/// <summary>
/// Creates a new instance of <see cref="ActionEventHandler{TEventData}"/>.
/// </summary>
/// <param name="handler">Action to handle the event</param>
public ActionEventHandler(Action<TEvent> handler)
{
Action = handler;
}
/// <summary>
/// Handles the event.
/// </summary>
/// <param name="eventData"></param>
public void HandleEvent(TEvent eventData)
{
Action(eventData);
}
}
}

167
src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBus.cs

@ -64,26 +64,13 @@ namespace Volo.Abp.EventBus
} }
/// <inheritdoc/> /// <inheritdoc/>
public IDisposable Register<TEvent>(Action<TEvent> action) public IDisposable Register<TEvent>(Func<TEvent, Task> action) where TEvent : class
where TEvent : class
{
return Register(typeof(TEvent), new ActionEventHandler<TEvent>(action));
}
/// <inheritdoc/>
public IDisposable AsyncRegister<TEvent>(Func<TEvent, Task> action) where TEvent : class
{ {
return Register(typeof(TEvent), new AsyncActionEventHandler<TEvent>(action)); return Register(typeof(TEvent), new AsyncActionEventHandler<TEvent>(action));
} }
/// <inheritdoc/> /// <inheritdoc/>
public IDisposable Register<TEvent>(IEventHandler<TEvent> handler) where TEvent : class public IDisposable Register<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{
return Register(typeof(TEvent), handler);
}
/// <inheritdoc/>
public IDisposable AsyncRegister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{ {
return Register(typeof(TEvent), handler); return Register(typeof(TEvent), handler);
} }
@ -117,34 +104,6 @@ namespace Volo.Abp.EventBus
return new EventHandlerFactoryUnregistrar(this, eventType, factory); return new EventHandlerFactoryUnregistrar(this, eventType, factory);
} }
/// <inheritdoc/>
public void Unregister<TEvent>(Action<TEvent> action) where TEvent : class
{
Check.NotNull(action, nameof(action));
GetOrCreateHandlerFactories(typeof(TEvent))
.Locking(factories =>
{
factories.RemoveAll(
factory =>
{
var singleInstanceFactory = factory as SingleInstanceHandlerFactory;
if (singleInstanceFactory == null)
{
return false;
}
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEvent>;
if (actionHandler == null)
{
return false;
}
return actionHandler.Action == action;
});
});
}
/// <inheritdoc/> /// <inheritdoc/>
public void AsyncUnregister<TEvent>(Func<TEvent, Task> action) where TEvent : class public void AsyncUnregister<TEvent>(Func<TEvent, Task> action) where TEvent : class
{ {
@ -173,12 +132,6 @@ namespace Volo.Abp.EventBus
}); });
} }
/// <inheritdoc/>
public void Unregister<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
Unregister(typeof(TEvent), handler);
}
/// <inheritdoc/> /// <inheritdoc/>
public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{ {
@ -223,66 +176,6 @@ namespace Volo.Abp.EventBus
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
} }
/// <inheritdoc/>
public void Trigger<TEvent>(TEvent eventData) where TEvent : class
{
Trigger(typeof(TEvent), eventData);
}
/// <inheritdoc/>
public void Trigger(Type eventType, object eventData)
{
var exceptions = new List<Exception>();
foreach (var handlerFactories in GetHandlerFactories(eventType))
{
foreach (var handlerFactory in handlerFactories.EventHandlerFactories)
{
var handlerType = handlerFactory.GetHandlerType();
if (IsAsyncEventHandler(handlerType))
{
AsyncHelper.RunSync(() => TriggerAsyncHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions));
}
else if (IsEventHandler(handlerType))
{
TriggerHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions);
}
else
{
var message = $"Event handler to register for event type {eventType.Name} does not implement IEventHandler<{eventType.Name}> or IAsyncEventHandler<{eventType.Name}> interface!";
exceptions.Add(new AbpException(message));
}
}
}
//Implements generic argument inheritance. See classWithInheritableGenericArgument
if (eventType.GetTypeInfo().IsGenericType &&
eventType.GetGenericArguments().Length == 1 &&
typeof(IEventDataWithInheritableGenericArgument).IsAssignableFrom(eventType))
{
var genericArg = eventType.GetGenericArguments()[0];
var baseArg = genericArg.GetTypeInfo().BaseType;
if (baseArg != null)
{
var baseEventType = eventType.GetGenericTypeDefinition().MakeGenericType(baseArg);
var constructorArgs = ((IEventDataWithInheritableGenericArgument)eventData).GetConstructorArgs();
var baseEventData = Activator.CreateInstance(baseEventType, constructorArgs);
Trigger(baseEventType, baseEventData);
}
}
if (exceptions.Any())
{
if (exceptions.Count == 1)
{
exceptions[0].ReThrow();
}
throw new AggregateException("More than one error has occurred while triggering the event: " + eventType, exceptions);
}
}
/// <inheritdoc/> /// <inheritdoc/>
public Task TriggerAsync<TEvent>(TEvent eventData) where TEvent : class public Task TriggerAsync<TEvent>(TEvent eventData) where TEvent : class
{ {
@ -300,21 +193,7 @@ namespace Volo.Abp.EventBus
{ {
foreach (var handlerFactory in handlerFactories.EventHandlerFactories) foreach (var handlerFactory in handlerFactories.EventHandlerFactories)
{ {
var handlerType = handlerFactory.GetHandlerType(); await TriggerAsyncHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions);
if (IsAsyncEventHandler(handlerType))
{
await TriggerAsyncHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions);
}
else if (IsEventHandler(handlerType))
{
TriggerHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions);
}
else
{
var message = $"Event handler to register for event type {eventType.Name} does not implement IEventHandler<{eventType.Name}> or IAsyncEventHandler<{eventType.Name}> interface!";
exceptions.Add(new AbpException(message));
}
} }
} }
@ -345,32 +224,6 @@ namespace Volo.Abp.EventBus
} }
} }
private void TriggerHandlingException(IEventHandlerFactory handlerFactory, Type eventType, object eventData, List<Exception> exceptions)
{
using (var eventHandlerWrapper = handlerFactory.GetHandler())
{
try
{
var handlerType = typeof(IEventHandler<>).MakeGenericType(eventType);
var method = handlerType.GetMethod(
"HandleEvent",
new[] { eventType }
);
method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData });
}
catch (TargetInvocationException ex)
{
exceptions.Add(ex.InnerException);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
}
private async Task TriggerAsyncHandlingException(IEventHandlerFactory asyncHandlerFactory, Type eventType, object eventData, List<Exception> exceptions) private async Task TriggerAsyncHandlingException(IEventHandlerFactory asyncHandlerFactory, Type eventType, object eventData, List<Exception> exceptions)
{ {
using (var eventHandlerWrapper = asyncHandlerFactory.GetHandler()) using (var eventHandlerWrapper = asyncHandlerFactory.GetHandler())
@ -397,20 +250,6 @@ namespace Volo.Abp.EventBus
} }
} }
private bool IsEventHandler(Type handlerType)
{
return handlerType.GetInterfaces()
.Where(i => i.IsGenericType)
.Any(i => i.GetGenericTypeDefinition() == typeof(IEventHandler<>));
}
private bool IsAsyncEventHandler(Type handlerType)
{
return handlerType.GetInterfaces()
.Where(i => i.IsGenericType)
.Any(i => i.GetGenericTypeDefinition() == typeof(IAsyncEventHandler<>));
}
private IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType) private IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{ {
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>(); var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();

65
src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs

@ -8,33 +8,13 @@ namespace Volo.Abp.EventBus
/// </summary> /// </summary>
public interface IEventBus public interface IEventBus
{ {
#region Register
/// <summary>
/// Registers to an event.
/// Given action is called for all event occurrences.
/// </summary>
/// <param name="action">Action to handle events</param>
/// <typeparam name="TEvent">Event type</typeparam>
IDisposable Register<TEvent>(Action<TEvent> action)
where TEvent : class;
/// <summary> /// <summary>
/// Registers to an event. /// Registers to an event.
/// Given action is called for all event occurrences. /// Given action is called for all event occurrences.
/// </summary> /// </summary>
/// <param name="action">Action to handle events</param> /// <param name="action">Action to handle events</param>
/// <typeparam name="TEvent">Event type</typeparam> /// <typeparam name="TEvent">Event type</typeparam>
IDisposable AsyncRegister<TEvent>(Func<TEvent, Task> action) IDisposable Register<TEvent>(Func<TEvent, Task> action)
where TEvent : class;
/// <summary>
/// Registers to an event.
/// Same (given) instance of the handler is used for all event occurrences.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="handler">Object to handle the event</param>
IDisposable Register<TEvent>(IEventHandler<TEvent> handler)
where TEvent : class; where TEvent : class;
/// <summary> /// <summary>
@ -43,7 +23,7 @@ namespace Volo.Abp.EventBus
/// </summary> /// </summary>
/// <typeparam name="TEvent">Event type</typeparam> /// <typeparam name="TEvent">Event type</typeparam>
/// <param name="handler">Object to handle the event</param> /// <param name="handler">Object to handle the event</param>
IDisposable AsyncRegister<TEvent>(IAsyncEventHandler<TEvent> handler) IDisposable Register<TEvent>(IAsyncEventHandler<TEvent> handler)
where TEvent : class; where TEvent : class;
/// <summary> /// <summary>
@ -80,18 +60,6 @@ namespace Volo.Abp.EventBus
/// <param name="factory">A factory to create/release handlers</param> /// <param name="factory">A factory to create/release handlers</param>
IDisposable Register(Type eventType, IEventHandlerFactory factory); IDisposable Register(Type eventType, IEventHandlerFactory factory);
#endregion
#region Unregister
/// <summary>
/// Unregisters from an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="action"></param>
void Unregister<TEvent>(Action<TEvent> action)
where TEvent : class;
/// <summary> /// <summary>
/// Unregisters from an event. /// Unregisters from an event.
/// </summary> /// </summary>
@ -100,14 +68,6 @@ namespace Volo.Abp.EventBus
void AsyncUnregister<TEvent>(Func<TEvent, Task> action) void AsyncUnregister<TEvent>(Func<TEvent, Task> action)
where TEvent : class; where TEvent : class;
/// <summary>
/// Unregisters from an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="handler">Handler object that is registered before</param>
void Unregister<TEvent>(IEventHandler<TEvent> handler)
where TEvent : class;
/// <summary> /// <summary>
/// Unregisters from an event. /// Unregisters from an event.
/// </summary> /// </summary>
@ -151,25 +111,6 @@ namespace Volo.Abp.EventBus
/// <param name="eventType">Event type</param> /// <param name="eventType">Event type</param>
void UnregisterAll(Type eventType); void UnregisterAll(Type eventType);
#endregion
#region Trigger
/// <summary>
/// Triggers an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="eventData">Related data for the event</param>
void Trigger<TEvent>(TEvent eventData)
where TEvent : class;
/// <summary>
/// Triggers an event.
/// </summary>
/// <param name="eventType">Event type</param>
/// <param name="eventData">Related data for the event</param>
void Trigger(Type eventType, object eventData);
/// <summary> /// <summary>
/// Triggers an event asynchronously. /// Triggers an event asynchronously.
/// </summary> /// </summary>
@ -186,7 +127,5 @@ namespace Volo.Abp.EventBus
/// <param name="eventData">Related data for the event</param> /// <param name="eventData">Related data for the event</param>
/// <returns>The task to handle async operation</returns> /// <returns>The task to handle async operation</returns>
Task TriggerAsync(Type eventType, object eventData); Task TriggerAsync(Type eventType, object eventData);
#endregion
} }
} }

15
src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandler.cs

@ -2,23 +2,10 @@ namespace Volo.Abp.EventBus
{ {
/// <summary> /// <summary>
/// Undirect base interface for all event handlers. /// Undirect base interface for all event handlers.
/// Implement <see cref="IEventHandler{TEventData}"/> instead of this one. /// Implement <see cref="IAsyncEventHandler{TEventData}"/> instead of this one.
/// </summary> /// </summary>
public interface IEventHandler public interface IEventHandler
{ {
} }
/// <summary>
/// Defines an interface of a class that handles events of type <see cref="IEventHandler{TEventData}"/>.
/// </summary>
/// <typeparam name="TEvent">Event type to handle</typeparam>
public interface IEventHandler<in TEvent> : IEventHandler
{
/// <summary>
/// Handler handles the event by implementing this method.
/// </summary>
/// <param name="eventData">Event data</param>
void HandleEvent(TEvent eventData);
}
} }

8
src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerFactory.cs

@ -1,5 +1,3 @@
using System;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
{ {
/// <summary> /// <summary>
@ -12,11 +10,5 @@ namespace Volo.Abp.EventBus
/// </summary> /// </summary>
/// <returns>The event handler</returns> /// <returns>The event handler</returns>
IEventHandlerDisposeWrapper GetHandler(); IEventHandlerDisposeWrapper GetHandler();
/// <summary>
/// Gets type of the handler (without creating an instance).
/// </summary>
/// <returns></returns>
Type GetHandlerType();
} }
} }

5
src/Volo.Abp.EventBus/Volo/Abp/EventBus/IocEventHandlerFactory.cs

@ -31,10 +31,5 @@ namespace Volo.Abp.EventBus
() => scope.Dispose() () => scope.Dispose()
); );
} }
public Type GetHandlerType()
{
return HandlerType;
}
} }
} }

34
src/Volo.Abp.EventBus/Volo/Abp/EventBus/NullEventBus.cs

@ -12,22 +12,12 @@ namespace Volo.Abp.EventBus
} }
public IDisposable Register<TEvent>(Action<TEvent> action) where TEvent : class public IDisposable Register<TEvent>(Func<TEvent, Task> action) where TEvent : class
{ {
return NullDisposable.Instance; return NullDisposable.Instance;
} }
public IDisposable AsyncRegister<TEvent>(Func<TEvent, Task> action) where TEvent : class public IDisposable Register<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{
return NullDisposable.Instance;
}
public IDisposable Register<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
return NullDisposable.Instance;
}
public IDisposable AsyncRegister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{ {
return NullDisposable.Instance; return NullDisposable.Instance;
} }
@ -52,21 +42,11 @@ namespace Volo.Abp.EventBus
return NullDisposable.Instance; return NullDisposable.Instance;
} }
public void Unregister<TEvent>(Action<TEvent> action) where TEvent : class
{
}
public void AsyncUnregister<TEvent>(Func<TEvent, Task> action) where TEvent : class public void AsyncUnregister<TEvent>(Func<TEvent, Task> action) where TEvent : class
{ {
} }
public void Unregister<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
}
public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{ {
@ -97,16 +77,6 @@ namespace Volo.Abp.EventBus
} }
public void Trigger<TEvent>(TEvent eventData) where TEvent : class
{
}
public void Trigger(Type eventType, object eventData)
{
}
public Task TriggerAsync<TEvent>(TEvent eventData) where TEvent : class public Task TriggerAsync<TEvent>(TEvent eventData) where TEvent : class
{ {
return Task.CompletedTask; return Task.CompletedTask;

8
src/Volo.Abp.EventBus/Volo/Abp/EventBus/SingleInstanceHandlerFactory.cs

@ -1,6 +1,3 @@
using System;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
{ {
/// <summary> /// <summary>
@ -30,10 +27,5 @@ namespace Volo.Abp.EventBus
{ {
return new EventHandlerDisposeWrapper(HandlerInstance); return new EventHandlerDisposeWrapper(HandlerInstance);
} }
public Type GetHandlerType()
{
return ProxyHelper.UnProxy(HandlerInstance).GetType();
}
} }
} }

5
src/Volo.Abp.EventBus/Volo/Abp/EventBus/TransientEventHandlerFactory.cs

@ -24,10 +24,5 @@ namespace Volo.Abp.EventBus
() => (handler as IDisposable)?.Dispose() () => (handler as IDisposable)?.Dispose()
); );
} }
public Type GetHandlerType()
{
return typeof(THandler);
}
} }
} }

56
src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs

@ -13,6 +13,7 @@ using Volo.Abp.EventBus;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MongoDB; using Volo.Abp.MongoDB;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
namespace Volo.Abp.Domain.Repositories.MongoDB namespace Volo.Abp.Domain.Repositories.MongoDB
{ {
@ -53,7 +54,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
* This is also true for other "ed" & "ing" events. * This is also true for other "ed" & "ing" events.
*/ */
ApplyAbpConceptsForAddedEntity(entity); AsyncHelper.RunSync(() => ApplyAbpConceptsForAddedEntityAsync(entity));
Collection.InsertOne(entity); Collection.InsertOne(entity);
@ -65,7 +66,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false, bool autoSave = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
ApplyAbpConceptsForAddedEntity(entity); //TODO: async? await ApplyAbpConceptsForAddedEntityAsync(entity);
await Collection.InsertOneAsync( await Collection.InsertOneAsync(
entity, entity,
@ -82,14 +83,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{ {
SetDeletionAuditProperties(entity); SetDeletionAuditProperties(entity);
TriggerEntityDeleteEvents(entity); AsyncHelper.RunSync(() => TriggerEntityDeleteEvents(entity));
} }
else else
{ {
TriggerEntityUpdateEvents(entity); AsyncHelper.RunSync(() => TriggerEntityUpdateEvents(entity));
} }
TriggerDomainEvents(entity); AsyncHelper.RunSync(() => TriggerDomainEventsAsync(entity));
Collection.ReplaceOne( Collection.ReplaceOne(
CreateEntityFilter(entity), CreateEntityFilter(entity),
@ -109,14 +110,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{ {
SetDeletionAuditProperties(entity); SetDeletionAuditProperties(entity);
TriggerEntityDeleteEvents(entity); await TriggerEntityDeleteEvents(entity);
} }
else else
{ {
TriggerEntityUpdateEvents(entity); await TriggerEntityUpdateEvents(entity);
} }
TriggerDomainEvents(entity); await TriggerDomainEventsAsync(entity);
await Collection.ReplaceOneAsync( await Collection.ReplaceOneAsync(
CreateEntityFilter(entity), CreateEntityFilter(entity),
@ -129,7 +130,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
public override void Delete(TEntity entity, bool autoSave = false) public override void Delete(TEntity entity, bool autoSave = false)
{ {
ApplyAbpConceptsForDeletedEntity(entity); AsyncHelper.RunSync(() => ApplyAbpConceptsForDeletedEntityAsync(entity));
if (entity is ISoftDelete softDeleteEntity) if (entity is ISoftDelete softDeleteEntity)
{ {
@ -152,7 +153,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
bool autoSave = false, bool autoSave = false,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
ApplyAbpConceptsForDeletedEntity(entity); await ApplyAbpConceptsForDeletedEntityAsync(entity);
if (entity is ISoftDelete softDeleteEntity) if (entity is ISoftDelete softDeleteEntity)
{ {
@ -220,37 +221,37 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
); );
} }
protected virtual void ApplyAbpConceptsForAddedEntity(TEntity entity) protected virtual async Task ApplyAbpConceptsForAddedEntityAsync(TEntity entity)
{ {
CheckAndSetId(entity); CheckAndSetId(entity);
SetCreationAuditProperties(entity); SetCreationAuditProperties(entity);
TriggerEntityCreateEvents(entity); await TriggerEntityCreateEvents(entity);
TriggerDomainEvents(entity); await TriggerDomainEventsAsync(entity);
} }
private void TriggerEntityCreateEvents(TEntity entity) private async Task TriggerEntityCreateEvents(TEntity entity)
{ {
EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompleted(entity); await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity);
EntityChangeEventHelper.TriggerEntityCreatingEvent(entity); await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity);
} }
protected virtual void TriggerEntityUpdateEvents(TEntity entity) protected virtual async Task TriggerEntityUpdateEvents(TEntity entity)
{ {
EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompleted(entity); await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity);
EntityChangeEventHelper.TriggerEntityUpdatingEvent(entity); await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity);
} }
protected virtual void ApplyAbpConceptsForDeletedEntity(TEntity entity) protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity)
{ {
SetDeletionAuditProperties(entity); SetDeletionAuditProperties(entity);
TriggerEntityDeleteEvents(entity); await TriggerEntityDeleteEvents(entity);
TriggerDomainEvents(entity); await TriggerDomainEventsAsync(entity);
} }
protected virtual void TriggerEntityDeleteEvents(TEntity entity) protected virtual async Task TriggerEntityDeleteEvents(TEntity entity)
{ {
EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompleted(entity); await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity);
EntityChangeEventHelper.TriggerEntityDeletingEvent(entity); await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity);
} }
protected virtual void CheckAndSetId(TEntity entity) protected virtual void CheckAndSetId(TEntity entity)
@ -276,8 +277,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
AuditPropertySetter.SetDeletionProperties(entity); AuditPropertySetter.SetDeletionProperties(entity);
} }
//TODO: TriggerDomainEventsAsync..? protected virtual async Task TriggerDomainEventsAsync(object entity)
protected virtual void TriggerDomainEvents(object entity)
{ {
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents; var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null) if (generatesDomainEventsEntity == null)
@ -293,7 +293,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
foreach (var entityEvent in entityEvents) foreach (var entityEvent in entityEvents)
{ {
EventBus.Trigger(entityEvent.GetType(), entityEvent); await EventBus.TriggerAsync(entityEvent.GetType(), entityEvent);
} }
generatesDomainEventsEntity.ClearDomainEvents(); generatesDomainEventsEntity.ClearDomainEvents();

7
src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs

@ -17,7 +17,6 @@ namespace Volo.Abp.Uow
public string ReservationName => _parent.ReservationName; public string ReservationName => _parent.ReservationName;
public event EventHandler<UnitOfWorkEventArgs> Completed;
public event EventHandler<UnitOfWorkFailedEventArgs> Failed; public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler<UnitOfWorkEventArgs> Disposed; public event EventHandler<UnitOfWorkEventArgs> Disposed;
@ -31,7 +30,6 @@ namespace Volo.Abp.Uow
_parent = parent; _parent = parent;
_parent.Completed += (sender, args) => { Completed.InvokeSafely(sender, args); };
_parent.Failed += (sender, args) => { Failed.InvokeSafely(sender, args); }; _parent.Failed += (sender, args) => { Failed.InvokeSafely(sender, args); };
_parent.Disposed += (sender, args) => { Disposed.InvokeSafely(sender, args); }; _parent.Disposed += (sender, args) => { Disposed.InvokeSafely(sender, args); };
} }
@ -81,6 +79,11 @@ namespace Volo.Abp.Uow
return _parent.RollbackAsync(cancellationToken); return _parent.RollbackAsync(cancellationToken);
} }
public void OnCompleted(Func<Task> handler)
{
_parent.OnCompleted(handler);
}
public IDatabaseApi FindDatabaseApi(string key) public IDatabaseApi FindDatabaseApi(string key)
{ {
return _parent.FindDatabaseApi(key); return _parent.FindDatabaseApi(key);

5
src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs

@ -9,8 +9,7 @@ namespace Volo.Abp.Uow
{ {
Guid Id { get; } Guid Id { get; }
event EventHandler<UnitOfWorkEventArgs> Completed; //TODO: Switch to OnFailed (sync) and OnDisposed (sync) methods to be compatible with OnCompleted
event EventHandler<UnitOfWorkFailedEventArgs> Failed; event EventHandler<UnitOfWorkFailedEventArgs> Failed;
event EventHandler<UnitOfWorkEventArgs> Disposed; event EventHandler<UnitOfWorkEventArgs> Disposed;
@ -40,5 +39,7 @@ namespace Volo.Abp.Uow
void Rollback(); void Rollback();
Task RollbackAsync(CancellationToken cancellationToken = default); Task RollbackAsync(CancellationToken cancellationToken = default);
void OnCompleted(Func<Task> handler);
} }
} }

29
src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs

@ -4,6 +4,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Uow namespace Volo.Abp.Uow
{ {
@ -19,7 +20,8 @@ namespace Volo.Abp.Uow
public string ReservationName { get; set; } public string ReservationName { get; set; }
public event EventHandler<UnitOfWorkEventArgs> Completed; protected List<Func<Task>> CompletedHandlers { get; } = new List<Func<Task>>();
public event EventHandler<UnitOfWorkFailedEventArgs> Failed; public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler<UnitOfWorkEventArgs> Disposed; public event EventHandler<UnitOfWorkEventArgs> Disposed;
@ -123,7 +125,7 @@ namespace Volo.Abp.Uow
{ {
await SaveChangesAsync(cancellationToken); await SaveChangesAsync(cancellationToken);
await CommitTransactionsAsync(); await CommitTransactionsAsync();
OnCompleted(); await OnCompletedAsync();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -210,9 +212,30 @@ namespace Volo.Abp.Uow
return _transactionApis.GetOrAdd(key, factory); return _transactionApis.GetOrAdd(key, factory);
} }
public void OnCompleted(Func<Task> handler)
{
CompletedHandlers.Add(handler);
}
public void OnFailed(Func<Task> handler)
{
throw new NotImplementedException();
}
protected virtual void OnCompleted() protected virtual void OnCompleted()
{ {
Completed.InvokeSafely(this, new UnitOfWorkEventArgs(this)); foreach (var handler in CompletedHandlers)
{
AsyncHelper.RunSync(handler);
}
}
protected virtual async Task OnCompletedAsync()
{
foreach (var handler in CompletedHandlers)
{
await handler.Invoke();
}
} }
protected virtual void OnFailed() protected virtual void OnFailed()

50
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/ActionBasedEventHandlerTest.cs

@ -8,7 +8,7 @@ namespace Volo.Abp.EventBus
public class ActionBasedEventHandlerTest : EventBusTestBase public class ActionBasedEventHandlerTest : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Call_Action_On_Event_With_Correct_Source() public async Task Should_Call_Action_On_Event_With_Correct_Source()
{ {
var totalData = 0; var totalData = 0;
@ -16,18 +16,19 @@ namespace Volo.Abp.EventBus
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
EventBus.Trigger(new MySimpleEventData(2)); await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3)); await EventBus.TriggerAsync(new MySimpleEventData(3));
EventBus.Trigger(new MySimpleEventData(4)); await EventBus.TriggerAsync(new MySimpleEventData(4));
Assert.Equal(10, totalData); Assert.Equal(10, totalData);
} }
[Fact] [Fact]
public void Should_Call_Handler_With_Non_Generic_Trigger() public async Task Should_Call_Handler_With_Non_Generic_Trigger()
{ {
var totalData = 0; var totalData = 0;
@ -35,18 +36,19 @@ namespace Volo.Abp.EventBus
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Trigger(typeof(MySimpleEventData), new MySimpleEventData(1)); await EventBus.TriggerAsync(typeof(MySimpleEventData), new MySimpleEventData(1));
EventBus.Trigger(typeof(MySimpleEventData), new MySimpleEventData(2)); await EventBus.TriggerAsync(typeof(MySimpleEventData), new MySimpleEventData(2));
EventBus.Trigger(typeof(MySimpleEventData), new MySimpleEventData(3)); await EventBus.TriggerAsync(typeof(MySimpleEventData), new MySimpleEventData(3));
EventBus.Trigger(typeof(MySimpleEventData), new MySimpleEventData(4)); await EventBus.TriggerAsync(typeof(MySimpleEventData), new MySimpleEventData(4));
Assert.Equal(10, totalData); Assert.Equal(10, totalData);
} }
[Fact] [Fact]
public void Should_Not_Call_Action_After_Unregister_1() public async Task Should_Not_Call_Action_After_Unregister_1()
{ {
var totalData = 0; var totalData = 0;
@ -54,39 +56,41 @@ namespace Volo.Abp.EventBus
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
EventBus.Trigger(new MySimpleEventData(2)); await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3)); await EventBus.TriggerAsync(new MySimpleEventData(3));
registerDisposer.Dispose(); registerDisposer.Dispose();
EventBus.Trigger(new MySimpleEventData(4)); await EventBus.TriggerAsync(new MySimpleEventData(4));
Assert.Equal(6, totalData); Assert.Equal(6, totalData);
} }
[Fact] [Fact]
public void Should_Not_Call_Action_After_Unregister_2() public async Task Should_Not_Call_Action_After_Unregister_2()
{ {
var totalData = 0; var totalData = 0;
var action = new Action<MySimpleEventData>( var action = new Func<MySimpleEventData, Task>(
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Register(action); EventBus.Register(action);
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
EventBus.Trigger(new MySimpleEventData(2)); await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3)); await EventBus.TriggerAsync(new MySimpleEventData(3));
EventBus.Unregister(action); EventBus.AsyncUnregister(action);
EventBus.Trigger(new MySimpleEventData(4)); await EventBus.TriggerAsync(new MySimpleEventData(4));
Assert.Equal(6, totalData); Assert.Equal(6, totalData);
} }
@ -96,7 +100,7 @@ namespace Volo.Abp.EventBus
{ {
int totalData = 0; int totalData = 0;
EventBus.AsyncRegister<MySimpleEventData>( EventBus.Register<MySimpleEventData>(
async eventData => async eventData =>
{ {
await Task.Delay(20); await Task.Delay(20);

4
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_DI_Services_Test.cs

@ -9,9 +9,9 @@ namespace Volo.Abp.EventBus
[Fact] [Fact]
public async Task Should_Automatically_Register_EventHandlers_From_Services() public async Task Should_Automatically_Register_EventHandlers_From_Services()
{ {
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
await EventBus.TriggerAsync(new MySimpleEventData(2)); await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3)); await EventBus.TriggerAsync(new MySimpleEventData(3));
await EventBus.TriggerAsync(new MySimpleEventData(4)); await EventBus.TriggerAsync(new MySimpleEventData(4));
GetRequiredService<MySimpleEventDataHandler>().TotalData.ShouldBe(10); GetRequiredService<MySimpleEventDataHandler>().TotalData.ShouldBe(10);

16
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_Exception_Test.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Xunit; using Xunit;
@ -7,21 +8,20 @@ namespace Volo.Abp.EventBus
public class EventBus_Exception_Test : EventBusTestBase public class EventBus_Exception_Test : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Throw_Single_Exception_If_Only_One_Of_Handlers_Fails() public async Task Should_Throw_Single_Exception_If_Only_One_Of_Handlers_Fails()
{ {
EventBus.Register<MySimpleEventData>( EventBus.Register<MySimpleEventData>(eventData => throw new Exception("This exception is intentionally thrown!"));
eventData => throw new Exception("This exception is intentionally thrown!"));
var appException = Assert.Throws<Exception>(() => var appException = await Assert.ThrowsAsync<Exception>(async () =>
{ {
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
}); });
appException.Message.ShouldBe("This exception is intentionally thrown!"); appException.Message.ShouldBe("This exception is intentionally thrown!");
} }
[Fact] [Fact]
public void Should_Throw_Aggregate_Exception_If_More_Than_One_Of_Handlers_Fail() public async Task Should_Throw_Aggregate_Exception_If_More_Than_One_Of_Handlers_Fail()
{ {
EventBus.Register<MySimpleEventData>( EventBus.Register<MySimpleEventData>(
eventData => throw new Exception("This exception is intentionally thrown #1!")); eventData => throw new Exception("This exception is intentionally thrown #1!"));
@ -29,9 +29,9 @@ namespace Volo.Abp.EventBus
EventBus.Register<MySimpleEventData>( EventBus.Register<MySimpleEventData>(
eventData => throw new Exception("This exception is intentionally thrown #2!")); eventData => throw new Exception("This exception is intentionally thrown #2!"));
var aggrException = Assert.Throws<AggregateException>(() => var aggrException = await Assert.ThrowsAsync<AggregateException>(async () =>
{ {
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
}); });
aggrException.InnerExceptions.Count.ShouldBe(2); aggrException.InnerExceptions.Count.ShouldBe(2);

20
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/EventBus_MultipleHandle_Test.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.EventBus
public class EventBus_EntityEvents_Test : EventBusTestBase public class EventBus_EntityEvents_Test : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Call_Created_And_Changed_Once() public async Task Should_Call_Created_And_Changed_Once()
{ {
var handler = new MyEventHandler(); var handler = new MyEventHandler();
@ -18,10 +18,10 @@ namespace Volo.Abp.EventBus
var asyncHandler = new MyAsyncEventHandler(); var asyncHandler = new MyAsyncEventHandler();
EventBus.AsyncRegister<EntityChangedEventData<MyEntity>>(asyncHandler); EventBus.Register<EntityChangedEventData<MyEntity>>(asyncHandler);
EventBus.AsyncRegister<EntityCreatedEventData<MyEntity>>(asyncHandler); EventBus.Register<EntityCreatedEventData<MyEntity>>(asyncHandler);
EventBus.Trigger(new EntityCreatedEventData<MyEntity>(new MyEntity())); await EventBus.TriggerAsync(new EntityCreatedEventData<MyEntity>(new MyEntity()));
handler.EntityCreatedEventCount.ShouldBe(1); handler.EntityCreatedEventCount.ShouldBe(1);
handler.EntityChangedEventCount.ShouldBe(1); handler.EntityChangedEventCount.ShouldBe(1);
@ -35,21 +35,23 @@ namespace Volo.Abp.EventBus
} }
public class MyEventHandler : public class MyEventHandler :
IEventHandler<EntityChangedEventData<MyEntity>>, IAsyncEventHandler<EntityChangedEventData<MyEntity>>,
IEventHandler<EntityCreatedEventData<MyEntity>> IAsyncEventHandler<EntityCreatedEventData<MyEntity>>
{ {
public int EntityChangedEventCount { get; set; } public int EntityChangedEventCount { get; set; }
public int EntityCreatedEventCount { get; set; } public int EntityCreatedEventCount { get; set; }
public void HandleEvent(EntityChangedEventData<MyEntity> eventData) public Task HandleEventAsync(EntityChangedEventData<MyEntity> eventData)
{ {
EntityChangedEventCount++; EntityChangedEventCount++;
return Task.CompletedTask;
} }
public void HandleEvent(EntityCreatedEventData<MyEntity> eventData) public Task HandleEventAsync(EntityCreatedEventData<MyEntity> eventData)
{ {
EntityCreatedEventCount++; EntityCreatedEventCount++;
return Task.CompletedTask;
} }
} }

12
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/GenericInheritanceTest.cs

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
@ -8,7 +9,7 @@ namespace Volo.Abp.EventBus
public class GenericInheritanceTest : EventBusTestBase public class GenericInheritanceTest : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Trigger_For_Inherited_Generic_1() public async Task Should_Trigger_For_Inherited_Generic_1()
{ {
var triggeredEvent = false; var triggeredEvent = false;
@ -17,15 +18,16 @@ namespace Volo.Abp.EventBus
{ {
eventData.Entity.Id.ShouldBe(42); eventData.Entity.Id.ShouldBe(42);
triggeredEvent = true; triggeredEvent = true;
return Task.CompletedTask;
}); });
EventBus.Trigger(new EntityUpdatedEventData<Person>(new Person { Id = 42 })); await EventBus.TriggerAsync(new EntityUpdatedEventData<Person>(new Person { Id = 42 }));
triggeredEvent.ShouldBe(true); triggeredEvent.ShouldBe(true);
} }
[Fact] [Fact]
public void Should_Trigger_For_Inherited_Generic_2() public async Task Should_Trigger_For_Inherited_Generic_2()
{ {
var triggeredEvent = false; var triggeredEvent = false;
@ -34,14 +36,14 @@ namespace Volo.Abp.EventBus
{ {
eventData.Entity.Id.ShouldBe(42); eventData.Entity.Id.ShouldBe(42);
triggeredEvent = true; triggeredEvent = true;
return Task.CompletedTask;
}); });
EventBus.Trigger(new EntityChangedEventData<Student>(new Student { Id = 42 })); await EventBus.TriggerAsync(new EntityChangedEventData<Student>(new Student { Id = 42 }));
triggeredEvent.ShouldBe(true); triggeredEvent.ShouldBe(true);
} }
public class Person : Entity<int> public class Person : Entity<int>
{ {

23
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/InheritanceTest.cs

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
@ -5,7 +6,7 @@ namespace Volo.Abp.EventBus
public class InheritanceTest : EventBusTestBase public class InheritanceTest : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Handle_Events_For_Derived_Classes() public async Task Should_Handle_Events_For_Derived_Classes()
{ {
var totalData = 0; var totalData = 0;
@ -13,18 +14,19 @@ namespace Volo.Abp.EventBus
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Trigger(new MySimpleEventData(1)); //Should handle directly registered class await EventBus.TriggerAsync(new MySimpleEventData(1)); //Should handle directly registered class
EventBus.Trigger(new MySimpleEventData(2)); //Should handle directly registered class await EventBus.TriggerAsync(new MySimpleEventData(2)); //Should handle directly registered class
EventBus.Trigger(new MyDerivedEventData(3)); //Should handle derived class too await EventBus.TriggerAsync(new MyDerivedEventData(3)); //Should handle derived class too
EventBus.Trigger(new MyDerivedEventData(4)); //Should handle derived class too await EventBus.TriggerAsync(new MyDerivedEventData(4)); //Should handle derived class too
Assert.Equal(10, totalData); Assert.Equal(10, totalData);
} }
[Fact] [Fact]
public void Should_Not_Handle_Events_For_Base_Classes() public async Task Should_Not_Handle_Events_For_Base_Classes()
{ {
var totalData = 0; var totalData = 0;
@ -32,12 +34,13 @@ namespace Volo.Abp.EventBus
eventData => eventData =>
{ {
totalData += eventData.Value; totalData += eventData.Value;
return Task.CompletedTask;
}); });
EventBus.Trigger(new MySimpleEventData(1)); //Should not handle await EventBus.TriggerAsync(new MySimpleEventData(1)); //Should not handle
EventBus.Trigger(new MySimpleEventData(2)); //Should not handle await EventBus.TriggerAsync(new MySimpleEventData(2)); //Should not handle
EventBus.Trigger(new MyDerivedEventData(3)); //Should handle await EventBus.TriggerAsync(new MyDerivedEventData(3)); //Should handle
EventBus.Trigger(new MyDerivedEventData(4)); //Should handle await EventBus.TriggerAsync(new MyDerivedEventData(4)); //Should handle
Assert.Equal(7, totalData); Assert.Equal(7, totalData);
} }

8
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleEventDataHandler.cs

@ -1,14 +1,16 @@
using Volo.Abp.DependencyInjection; using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
{ {
public class MySimpleEventDataHandler : IEventHandler<MySimpleEventData>, ISingletonDependency public class MySimpleEventDataHandler : IAsyncEventHandler<MySimpleEventData>, ISingletonDependency
{ {
public int TotalData { get; private set; } public int TotalData { get; private set; }
public void HandleEvent(MySimpleEventData eventData) public Task HandleEventAsync(MySimpleEventData eventData)
{ {
TotalData += eventData.Value; TotalData += eventData.Value;
return Task.CompletedTask;
} }
} }
} }

6
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/MySimpleTransientEventHandler.cs

@ -1,16 +1,18 @@
using System; using System;
using System.Threading.Tasks;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
{ {
public class MySimpleTransientEventHandler : IEventHandler<MySimpleEventData>, IDisposable public class MySimpleTransientEventHandler : IAsyncEventHandler<MySimpleEventData>, IDisposable
{ {
public static int HandleCount { get; set; } public static int HandleCount { get; set; }
public static int DisposeCount { get; set; } public static int DisposeCount { get; set; }
public void HandleEvent(MySimpleEventData eventData) public Task HandleEventAsync(MySimpleEventData eventData)
{ {
++HandleCount; ++HandleCount;
return Task.CompletedTask;
} }
public void Dispose() public void Dispose()

9
test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/TransientDisposableEventHandlerTest.cs

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Xunit; using Xunit;
namespace Volo.Abp.EventBus namespace Volo.Abp.EventBus
@ -5,14 +6,14 @@ namespace Volo.Abp.EventBus
public class TransientDisposableEventHandlerTest : EventBusTestBase public class TransientDisposableEventHandlerTest : EventBusTestBase
{ {
[Fact] [Fact]
public void Should_Call_Handler_AndDispose() public async Task Should_Call_Handler_AndDispose()
{ {
EventBus.Register<MySimpleEventData, MySimpleTransientEventHandler>(); EventBus.Register<MySimpleEventData, MySimpleTransientEventHandler>();
EventBus.Register<MySimpleEventData, MySimpleTransientAsyncEventHandler>(); EventBus.Register<MySimpleEventData, MySimpleTransientAsyncEventHandler>();
EventBus.Trigger(new MySimpleEventData(1)); await EventBus.TriggerAsync(new MySimpleEventData(1));
EventBus.Trigger(new MySimpleEventData(2)); await EventBus.TriggerAsync(new MySimpleEventData(2));
EventBus.Trigger(new MySimpleEventData(3)); await EventBus.TriggerAsync(new MySimpleEventData(3));
Assert.Equal(3, MySimpleTransientEventHandler.HandleCount); Assert.Equal(3, MySimpleTransientEventHandler.HandleCount);
Assert.Equal(3, MySimpleTransientEventHandler.DisposeCount); Assert.Equal(3, MySimpleTransientEventHandler.DisposeCount);

3
test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs

@ -29,11 +29,12 @@ namespace Volo.Abp.TestApp.Testing
var isTriggered = false; var isTriggered = false;
EventBus.Register<PersonNameChangedEvent>((data) => EventBus.Register<PersonNameChangedEvent>(data =>
{ {
data.OldName.ShouldBe("Douglas"); data.OldName.ShouldBe("Douglas");
data.Person.Name.ShouldBe("Douglas-Changed"); data.Person.Name.ShouldBe("Douglas-Changed");
isTriggered = true; isTriggered = true;
return Task.CompletedTask;
}); });
//Act //Act

8
test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -50,6 +51,7 @@ namespace Volo.Abp.TestApp.Testing
data.Entity.Age.ShouldBe(15); data.Entity.Age.ShouldBe(15);
data.Entity.Age = 18; data.Entity.Age = 18;
PersonRepository.Update(data.Entity); PersonRepository.Update(data.Entity);
return Task.CompletedTask;
}); });
EventBus.Register<EntityCreatedEventData<Person>>(data => EventBus.Register<EntityCreatedEventData<Person>>(data =>
@ -63,6 +65,8 @@ namespace Volo.Abp.TestApp.Testing
data.Entity.Age.ShouldBe(18); data.Entity.Age.ShouldBe(18);
data.Entity.Name.ShouldBe(personName); data.Entity.Name.ShouldBe(personName);
return Task.CompletedTask;
}); });
EventBus.Register<EntityUpdatingEventData<Person>>(data => EventBus.Register<EntityUpdatingEventData<Person>>(data =>
@ -76,6 +80,8 @@ namespace Volo.Abp.TestApp.Testing
data.Entity.Name.ShouldBe(personName); data.Entity.Name.ShouldBe(personName);
data.Entity.Age.ShouldBe(18); data.Entity.Age.ShouldBe(18);
return Task.CompletedTask;
}); });
EventBus.Register<EntityUpdatedEventData<Person>>(data => EventBus.Register<EntityUpdatedEventData<Person>>(data =>
@ -89,6 +95,8 @@ namespace Volo.Abp.TestApp.Testing
data.Entity.Name.ShouldBe(personName); data.Entity.Name.ShouldBe(personName);
data.Entity.Age.ShouldBe(18); data.Entity.Age.ShouldBe(18);
return Task.CompletedTask;
}); });
PersonRepository.Insert(new Person(Guid.NewGuid(), personName, 15)); PersonRepository.Insert(new Person(Guid.NewGuid(), personName, 15));

10
test/Volo.Abp.Uow.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

@ -22,7 +22,7 @@ namespace Volo.Abp.Uow
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
uow.Completed += (sender, args) => completed = true; uow.OnCompleted(async () => completed = true);
uow.Disposed += (sender, args) => disposed = true; uow.Disposed += (sender, args) => disposed = true;
uow.Complete(); uow.Complete();
@ -43,7 +43,7 @@ namespace Volo.Abp.Uow
{ {
using (var childUow = _unitOfWorkManager.Begin()) using (var childUow = _unitOfWorkManager.Begin())
{ {
childUow.Completed += (sender, args) => completed = true; childUow.OnCompleted(async () => completed = true);
uow.Disposed += (sender, args) => disposed = true; uow.Disposed += (sender, args) => disposed = true;
childUow.Complete(); childUow.Complete();
@ -73,7 +73,7 @@ namespace Volo.Abp.Uow
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
uow.Completed += (sender, args) => completed = true; uow.OnCompleted(async () => completed = true);
uow.Failed += (sender, args) => failed = true; uow.Failed += (sender, args) => failed = true;
uow.Disposed += (sender, args) => disposed = true; uow.Disposed += (sender, args) => disposed = true;
} }
@ -94,7 +94,7 @@ namespace Volo.Abp.Uow
{ {
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
uow.Completed += (sender, args) => completed = true; uow.OnCompleted(async () => completed = true);
uow.Failed += (sender, args) => failed = true; uow.Failed += (sender, args) => failed = true;
uow.Disposed += (sender, args) => disposed = true; uow.Disposed += (sender, args) => disposed = true;
@ -118,7 +118,7 @@ namespace Volo.Abp.Uow
using (var uow = _unitOfWorkManager.Begin()) using (var uow = _unitOfWorkManager.Begin())
{ {
uow.Completed += (sender, args) => completed = true; uow.OnCompleted(async () => completed = true);
uow.Failed += (sender, args) => { failed = true; args.IsRolledback.ShouldBeTrue(); }; uow.Failed += (sender, args) => { failed = true; args.IsRolledback.ShouldBeTrue(); };
uow.Disposed += (sender, args) => disposed = true; uow.Disposed += (sender, args) => disposed = true;

Loading…
Cancel
Save