Merge pull request #279 from volosoft/async-eventbus

Remove Sync IEventBus API
pull/301/head
Halil İbrahim Kalkan 7 years ago committed by GitHub
commit b96f86b56f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,98 +23,86 @@ namespace Volo.Abp.Domain.Entities.Events
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)
{
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);
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);
await 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);
TriggerDomainEvents(changeReport.DomainEvents);
await TriggerEntityChangeEvents(changeReport.ChangedEntities);
await TriggerDomainEvents(changeReport.DomainEvents);
}
protected virtual void TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities)
protected virtual async Task TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities)
{
foreach (var changedEntity in changedEntities)
{
switch (changedEntity.ChangeType)
{
case EntityChangeType.Created:
TriggerEntityCreatingEvent(changedEntity.Entity);
TriggerEntityCreatedEventOnUowCompleted(changedEntity.Entity);
await TriggerEntityCreatingEventAsync(changedEntity.Entity);
await TriggerEntityCreatedEventOnUowCompletedAsync(changedEntity.Entity);
break;
case EntityChangeType.Updated:
TriggerEntityUpdatingEvent(changedEntity.Entity);
TriggerEntityUpdatedEventOnUowCompleted(changedEntity.Entity);
await TriggerEntityUpdatingEventAsync(changedEntity.Entity);
await TriggerEntityUpdatedEventOnUowCompletedAsync(changedEntity.Entity);
break;
case EntityChangeType.Deleted:
TriggerEntityDeletingEvent(changedEntity.Entity);
TriggerEntityDeletedEventOnUowCompleted(changedEntity.Entity);
await TriggerEntityDeletingEventAsync(changedEntity.Entity);
await TriggerEntityDeletedEventOnUowCompletedAsync(changedEntity.Entity);
break;
default:
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)
{
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 eventType = genericEventType.MakeGenericType(entityType);
if (triggerInCurrentUnitOfWork || _unitOfWorkManager.Current == null)
{
EventBus.Trigger(eventType, Activator.CreateInstance(eventType, entity));
await EventBus.TriggerAsync(eventType, Activator.CreateInstance(eventType, entity));
return;
}
_unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, Activator.CreateInstance(eventType, entity));
_unitOfWorkManager.Current.OnCompleted(() => EventBus.TriggerAsync(eventType, Activator.CreateInstance(eventType, entity)));
}
}
}

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

@ -17,54 +17,49 @@ namespace Volo.Abp.Domain.Entities.Events
}
public void TriggerEntityCreatingEvent(object entity)
public Task TriggerEntityCreatingEventAsync(object entity)
{
}
public void TriggerEntityCreatedEvent(object entity)
{
return Task.CompletedTask;
}
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)

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

@ -1,10 +1,11 @@
using System;
using System.Threading.Tasks;
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.
/// This event handler is an adapter to be able to use an action as <see cref="IEventHandler{TEvent}"/> implementation.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
internal class ActionEventHandler<TEvent> :
@ -12,15 +13,15 @@ namespace Volo.Abp.EventBus
ITransientDependency
{
/// <summary>
/// Action to handle the event.
/// Function to handle the event.
/// </summary>
public Action<TEvent> Action { get; private set; }
public Func<TEvent, Task> Action { get; }
/// <summary>
/// Creates a new instance of <see cref="ActionEventHandler{TEventData}"/>.
/// Creates a new instance of <see cref="ActionEventHandler{TEvent}"/>.
/// </summary>
/// <param name="handler">Action to handle the event</param>
public ActionEventHandler(Action<TEvent> handler)
public ActionEventHandler(Func<TEvent, Task> handler)
{
Action = handler;
}
@ -29,9 +30,9 @@ namespace Volo.Abp.EventBus
/// Handles the event.
/// </summary>
/// <param name="eventData"></param>
public void HandleEvent(TEvent eventData)
public async Task HandleEventAsync(TEvent eventData)
{
Action(eventData);
await Action(eventData);
}
}
}

@ -1,38 +0,0 @@
using System;
using System.Threading.Tasks;
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="IAsyncEventHandler{TEventData}"/> implementation.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
internal class AsyncActionEventHandler<TEvent> :
IAsyncEventHandler<TEvent>,
ITransientDependency
{
/// <summary>
/// Function to handle the event.
/// </summary>
public Func<TEvent, Task> Action { get; }
/// <summary>
/// Creates a new instance of <see cref="AsyncActionEventHandler{TEventData}"/>.
/// </summary>
/// <param name="handler">Action to handle the event</param>
public AsyncActionEventHandler(Func<TEvent, Task> handler)
{
Action = handler;
}
/// <summary>
/// Handles the event.
/// </summary>
/// <param name="eventData"></param>
public async Task HandleEventAsync(TEvent eventData)
{
await Action(eventData);
}
}
}

@ -64,30 +64,17 @@ namespace Volo.Abp.EventBus
}
/// <inheritdoc/>
public IDisposable Register<TEvent>(Action<TEvent> action)
where TEvent : class
public IDisposable Register<TEvent>(Func<TEvent, Task> action) 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));
}
/// <inheritdoc/>
public IDisposable Register<TEvent>(IEventHandler<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);
}
/// <inheritdoc/>
public IDisposable Register<TEvent, THandler>()
where TEvent : class
@ -117,34 +104,6 @@ namespace Volo.Abp.EventBus
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/>
public void AsyncUnregister<TEvent>(Func<TEvent, Task> action) where TEvent : class
{
@ -162,7 +121,7 @@ namespace Volo.Abp.EventBus
return false;
}
var actionHandler = singleInstanceFactory.HandlerInstance as AsyncActionEventHandler<TEvent>;
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEvent>;
if (actionHandler == null)
{
return false;
@ -174,13 +133,7 @@ namespace Volo.Abp.EventBus
}
/// <inheritdoc/>
public void Unregister<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
Unregister(typeof(TEvent), handler);
}
/// <inheritdoc/>
public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
public void AsyncUnregister<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
Unregister(typeof(TEvent), handler);
}
@ -223,66 +176,6 @@ namespace Volo.Abp.EventBus
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/>
public Task TriggerAsync<TEvent>(TEvent eventData) where TEvent : class
{
@ -300,21 +193,7 @@ namespace Volo.Abp.EventBus
{
foreach (var handlerFactory in handlerFactories.EventHandlerFactories)
{
var handlerType = handlerFactory.GetHandlerType();
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));
}
await TriggerAsyncHandlingException(handlerFactory, handlerFactories.EventType, eventData, exceptions);
}
}
@ -345,39 +224,13 @@ 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)
{
using (var eventHandlerWrapper = asyncHandlerFactory.GetHandler())
{
try
{
var asyncHandlerType = typeof(IAsyncEventHandler<>).MakeGenericType(eventType);
var asyncHandlerType = typeof(IEventHandler<>).MakeGenericType(eventType);
var method = asyncHandlerType.GetMethod(
"HandleEventAsync",
@ -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)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();

@ -1,17 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.EventBus
{
/// <summary>
/// Defines an interface of a class that handles events asynchrounously of type <see cref="IAsyncEventHandler{TEventData}"/>.
/// </summary>
/// <typeparam name="TEvent">Event type to handle</typeparam>
public interface IAsyncEventHandler<in TEvent> : IEventHandler
{
/// <summary>
/// Handler handles the event by implementing this method.
/// </summary>
/// <param name="eventData">Event data</param>
Task HandleEventAsync(TEvent eventData);
}
}

@ -8,33 +8,13 @@ namespace Volo.Abp.EventBus
/// </summary>
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>
/// 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 AsyncRegister<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)
IDisposable Register<TEvent>(Func<TEvent, Task> action)
where TEvent : class;
/// <summary>
@ -43,7 +23,7 @@ namespace Volo.Abp.EventBus
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="handler">Object to handle the event</param>
IDisposable AsyncRegister<TEvent>(IAsyncEventHandler<TEvent> handler)
IDisposable Register<TEvent>(IEventHandler<TEvent> handler)
where TEvent : class;
/// <summary>
@ -80,18 +60,6 @@ namespace Volo.Abp.EventBus
/// <param name="factory">A factory to create/release handlers</param>
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>
/// Unregisters from an event.
/// </summary>
@ -105,15 +73,7 @@ namespace Volo.Abp.EventBus
/// </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>
/// Unregisters from an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="handler">Handler object that is registered before</param>
void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler)
void AsyncUnregister<TEvent>(IEventHandler<TEvent> handler)
where TEvent : class;
/// <summary>
@ -151,25 +111,6 @@ namespace Volo.Abp.EventBus
/// <param name="eventType">Event type</param>
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>
/// Triggers an event asynchronously.
/// </summary>
@ -186,7 +127,5 @@ namespace Volo.Abp.EventBus
/// <param name="eventData">Related data for the event</param>
/// <returns>The task to handle async operation</returns>
Task TriggerAsync(Type eventType, object eventData);
#endregion
}
}

@ -1,8 +1,10 @@
using System.Threading.Tasks;
namespace Volo.Abp.EventBus
{
/// <summary>
/// Undirect base interface for all event handlers.
/// Implement <see cref="IEventHandler{TEventData}"/> instead of this one.
/// Implement <see cref="IEventHandler{TEvent}"/> instead of this one.
/// </summary>
public interface IEventHandler
{
@ -10,7 +12,7 @@ namespace Volo.Abp.EventBus
}
/// <summary>
/// Defines an interface of a class that handles events of type <see cref="IEventHandler{TEventData}"/>.
/// Defines an interface of a class that handles events asynchrounously of type <see cref="IEventHandler{TEvent}"/>.
/// </summary>
/// <typeparam name="TEvent">Event type to handle</typeparam>
public interface IEventHandler<in TEvent> : IEventHandler
@ -19,6 +21,6 @@ namespace Volo.Abp.EventBus
/// Handler handles the event by implementing this method.
/// </summary>
/// <param name="eventData">Event data</param>
void HandleEvent(TEvent eventData);
Task HandleEventAsync(TEvent eventData);
}
}

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

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

@ -12,12 +12,7 @@ namespace Volo.Abp.EventBus
}
public IDisposable Register<TEvent>(Action<TEvent> action) where TEvent : class
{
return NullDisposable.Instance;
}
public IDisposable AsyncRegister<TEvent>(Func<TEvent, Task> action) where TEvent : class
public IDisposable Register<TEvent>(Func<TEvent, Task> action) where TEvent : class
{
return NullDisposable.Instance;
}
@ -27,11 +22,6 @@ namespace Volo.Abp.EventBus
return NullDisposable.Instance;
}
public IDisposable AsyncRegister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
{
return NullDisposable.Instance;
}
public IDisposable Register<TEvent, THandler>() where TEvent : class where THandler : IEventHandler, new()
{
return NullDisposable.Instance;
@ -52,22 +42,12 @@ namespace Volo.Abp.EventBus
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 Unregister<TEvent>(IEventHandler<TEvent> handler) where TEvent : class
{
}
public void AsyncUnregister<TEvent>(IAsyncEventHandler<TEvent> handler) where TEvent : class
public void AsyncUnregister<TEvent>(IEventHandler<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
{
return Task.CompletedTask;

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

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

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

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

@ -9,8 +9,7 @@ namespace Volo.Abp.Uow
{
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<UnitOfWorkEventArgs> Disposed;
@ -40,5 +39,7 @@ namespace Volo.Abp.Uow
void Rollback();
Task RollbackAsync(CancellationToken cancellationToken = default);
void OnCompleted(Func<Task> handler);
}
}

@ -4,6 +4,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Uow
{
@ -19,7 +20,8 @@ namespace Volo.Abp.Uow
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<UnitOfWorkEventArgs> Disposed;
@ -123,7 +125,7 @@ namespace Volo.Abp.Uow
{
await SaveChangesAsync(cancellationToken);
await CommitTransactionsAsync();
OnCompleted();
await OnCompletedAsync();
}
catch (Exception ex)
{
@ -210,9 +212,30 @@ namespace Volo.Abp.Uow
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()
{
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()

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

@ -9,13 +9,12 @@ namespace Volo.Abp.EventBus
[Fact]
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));
EventBus.Trigger(new MySimpleEventData(3));
await EventBus.TriggerAsync(new MySimpleEventData(3));
await EventBus.TriggerAsync(new MySimpleEventData(4));
GetRequiredService<MySimpleEventDataHandler>().TotalData.ShouldBe(10);
GetRequiredService<MySimpleAsyncEventDataHandler>().TotalData.ShouldBe(10);
}
}
}

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
@ -7,21 +8,20 @@ namespace Volo.Abp.EventBus
public class EventBus_Exception_Test : EventBusTestBase
{
[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>(
eventData => throw new Exception("This exception is intentionally thrown!"));
EventBus.Register<MySimpleEventData>(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!");
}
[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>(
eventData => throw new Exception("This exception is intentionally thrown #1!"));
@ -29,9 +29,9 @@ namespace Volo.Abp.EventBus
EventBus.Register<MySimpleEventData>(
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);

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

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

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

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

@ -1,4 +1,5 @@
using Volo.Abp.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.EventBus
{
@ -6,9 +7,10 @@ namespace Volo.Abp.EventBus
{
public int TotalData { get; private set; }
public void HandleEvent(MySimpleEventData eventData)
public Task HandleEventAsync(MySimpleEventData eventData)
{
TotalData += eventData.Value;
return Task.CompletedTask;
}
}
}

@ -1,23 +0,0 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.EventBus
{
public class MySimpleTransientAsyncEventHandler : IAsyncEventHandler<MySimpleEventData>, IDisposable
{
public static int HandleCount { get; set; }
public static int DisposeCount { get; set; }
public Task HandleEventAsync(MySimpleEventData eventData)
{
++HandleCount;
return Task.FromResult(0);
}
public void Dispose()
{
++DisposeCount;
}
}
}

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
namespace Volo.Abp.EventBus
{
@ -8,9 +9,10 @@ namespace Volo.Abp.EventBus
public static int DisposeCount { get; set; }
public void HandleEvent(MySimpleEventData eventData)
public Task HandleEventAsync(MySimpleEventData eventData)
{
++HandleCount;
return Task.CompletedTask;
}
public void Dispose()

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

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

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

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

Loading…
Cancel
Save