mirror of https://github.com/abpframework/abp.git
19 changed files with 1199 additions and 5 deletions
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.EventBus</AssemblyName> |
|||
<PackageId>Volo.Abp.EventBus</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,13 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
public class AbpEventBusModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddAssemblyOf<AbpEventBusModule>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,495 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Factories; |
|||
using Volo.Abp.EventBus.Factories.Internals; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
using Volo.Abp.EventBus.Handlers.Internals; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
/// <summary>
|
|||
/// Implements EventBus as Singleton pattern.
|
|||
/// </summary>
|
|||
public class EventBus : IEventBus, ISingletonDependency |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the default <see cref="EventBus"/> instance.
|
|||
/// </summary>
|
|||
public static EventBus Instance { get; } = new EventBus(); |
|||
|
|||
/// <summary>
|
|||
/// Reference to the Logger.
|
|||
/// </summary>
|
|||
public ILogger<EventBus> Logger { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// All registered handler factories.
|
|||
/// Key: Type of the event
|
|||
/// Value: List of handler factories
|
|||
/// </summary>
|
|||
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="EventBus"/> instance.
|
|||
/// Instead of creating a new instace, you can use <see cref="Instance"/> to use Global <see cref="EventBus"/>.
|
|||
/// </summary>
|
|||
public EventBus() |
|||
{ |
|||
_handlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); |
|||
Logger = NullLogger<EventBus>.Instance; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register<TEventData>(Action<TEventData> action) |
|||
where TEventData : class |
|||
{ |
|||
return Register(typeof(TEventData), new ActionEventHandler<TEventData>(action)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable AsyncRegister<TEventData>(Func<TEventData, Task> action) where TEventData : class |
|||
{ |
|||
return Register(typeof(TEventData), new AsyncActionEventHandler<TEventData>(action)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register<TEventData>(IEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
return Register(typeof(TEventData), handler); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable AsyncRegister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
return Register(typeof(TEventData), handler); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register<TEventData, THandler>() |
|||
where TEventData : class |
|||
where THandler : IEventHandler, new() |
|||
{ |
|||
return Register(typeof(TEventData), new TransientEventHandlerFactory<THandler>()); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register(Type eventType, IEventHandler handler) |
|||
{ |
|||
return Register(eventType, new SingleInstanceHandlerFactory(handler)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register<TEventData>(IEventHandlerFactory factory) where TEventData : class |
|||
{ |
|||
return Register(typeof(TEventData), factory); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IDisposable Register(Type eventType, IEventHandlerFactory factory) |
|||
{ |
|||
GetOrCreateHandlerFactories(eventType) |
|||
.Locking(factories => factories.Add(factory)); |
|||
|
|||
return new FactoryUnregistrar(this, eventType, factory); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Unregister<TEventData>(Action<TEventData> action) where TEventData : class |
|||
{ |
|||
Check.NotNull(action, nameof(action)); |
|||
|
|||
GetOrCreateHandlerFactories(typeof(TEventData)) |
|||
.Locking(factories => |
|||
{ |
|||
factories.RemoveAll( |
|||
factory => |
|||
{ |
|||
var singleInstanceFactory = factory as SingleInstanceHandlerFactory; |
|||
if (singleInstanceFactory == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEventData>; |
|||
if (actionHandler == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return actionHandler.Action == action; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void AsyncUnregister<TEventData>(Func<TEventData, Task> action) where TEventData : class |
|||
{ |
|||
Check.NotNull(action, nameof(action)); |
|||
|
|||
GetOrCreateHandlerFactories(typeof(TEventData)) |
|||
.Locking(factories => |
|||
{ |
|||
factories.RemoveAll( |
|||
factory => |
|||
{ |
|||
var singleInstanceFactory = factory as SingleInstanceHandlerFactory; |
|||
if (singleInstanceFactory == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
var actionHandler = singleInstanceFactory.HandlerInstance as AsyncActionEventHandler<TEventData>; |
|||
if (actionHandler == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
return actionHandler.Action == action; |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Unregister<TEventData>(IEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
Unregister(typeof(TEventData), handler); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void AsyncUnregister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
Unregister(typeof(TEventData), handler); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Unregister(Type eventType, IEventHandler handler) |
|||
{ |
|||
GetOrCreateHandlerFactories(eventType) |
|||
.Locking(factories => |
|||
{ |
|||
factories.RemoveAll( |
|||
factory => |
|||
factory is SingleInstanceHandlerFactory && |
|||
(factory as SingleInstanceHandlerFactory).HandlerInstance == handler |
|||
); |
|||
}); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Unregister<TEventData>(IEventHandlerFactory factory) where TEventData : class |
|||
{ |
|||
Unregister(typeof(TEventData), factory); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Unregister(Type eventType, IEventHandlerFactory factory) |
|||
{ |
|||
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void UnregisterAll<TEventData>() where TEventData : class |
|||
{ |
|||
UnregisterAll(typeof(TEventData)); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void UnregisterAll(Type eventType) |
|||
{ |
|||
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Trigger<TEventData>(TEventData eventData) where TEventData : class |
|||
{ |
|||
Trigger(typeof(TEventData), 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<TEventData>(TEventData eventData) where TEventData : class |
|||
{ |
|||
return TriggerAsync(typeof(TEventData), eventData); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public async Task TriggerAsync(Type eventType, object eventData) |
|||
{ |
|||
var exceptions = new List<Exception>(); |
|||
|
|||
await new SynchronizationContextRemover(); |
|||
|
|||
foreach (var handlerFactories in GetHandlerFactories(eventType)) |
|||
{ |
|||
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)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
//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); |
|||
await TriggerAsync(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); |
|||
} |
|||
} |
|||
|
|||
private void TriggerHandlingException(IEventHandlerFactory handlerFactory, Type eventType, object eventData, List<Exception> exceptions) |
|||
{ |
|||
var eventHandler = handlerFactory.GetHandler(); |
|||
try |
|||
{ |
|||
if (eventHandler == null) |
|||
{ |
|||
throw new ArgumentNullException($"Registered event handler for event type {eventType.Name} is null!"); |
|||
} |
|||
|
|||
var handlerType = typeof(IEventHandler<>).MakeGenericType(eventType); |
|||
|
|||
var method = handlerType.GetMethod( |
|||
"HandleEvent", |
|||
new[] { eventType } |
|||
); |
|||
|
|||
method.Invoke(eventHandler, new[] { eventData }); |
|||
} |
|||
catch (TargetInvocationException ex) |
|||
{ |
|||
exceptions.Add(ex.InnerException); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
exceptions.Add(ex); |
|||
} |
|||
finally |
|||
{ |
|||
handlerFactory.ReleaseHandler(eventHandler); |
|||
} |
|||
} |
|||
|
|||
private async Task TriggerAsyncHandlingException(IEventHandlerFactory asyncHandlerFactory, Type eventType, object eventData, List<Exception> exceptions) |
|||
{ |
|||
var asyncEventHandler = asyncHandlerFactory.GetHandler(); |
|||
|
|||
try |
|||
{ |
|||
if (asyncEventHandler == null) |
|||
{ |
|||
throw new ArgumentNullException($"Registered async event handler for event type {eventType.Name} is null!"); |
|||
} |
|||
|
|||
var asyncHandlerType = typeof(IAsyncEventHandler<>).MakeGenericType(eventType); |
|||
|
|||
var method = asyncHandlerType.GetMethod( |
|||
"HandleEventAsync", |
|||
new[] { eventType } |
|||
); |
|||
|
|||
await (Task)method.Invoke(asyncEventHandler, new[] { eventData }); |
|||
} |
|||
catch (TargetInvocationException ex) |
|||
{ |
|||
exceptions.Add(ex.InnerException); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
exceptions.Add(ex); |
|||
} |
|||
finally |
|||
{ |
|||
asyncHandlerFactory.ReleaseHandler(asyncEventHandler); |
|||
} |
|||
} |
|||
|
|||
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>(); |
|||
|
|||
foreach (var handlerFactory in _handlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))) |
|||
{ |
|||
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)); |
|||
} |
|||
|
|||
return handlerFactoryList.ToArray(); |
|||
} |
|||
|
|||
private static bool ShouldTriggerEventForHandler(Type eventType, Type handlerType) |
|||
{ |
|||
//Should trigger same type
|
|||
if (handlerType == eventType) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
//Should trigger for inherited types
|
|||
if (handlerType.IsAssignableFrom(eventType)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) |
|||
{ |
|||
return _handlerFactories.GetOrAdd(eventType, (type) => new List<IEventHandlerFactory>()); |
|||
} |
|||
|
|||
private class EventTypeWithEventHandlerFactories |
|||
{ |
|||
public Type EventType { get; } |
|||
|
|||
public List<IEventHandlerFactory> EventHandlerFactories { get; } |
|||
|
|||
public EventTypeWithEventHandlerFactories(Type eventType, List<IEventHandlerFactory> eventHandlerFactories) |
|||
{ |
|||
EventType = eventType; |
|||
EventHandlerFactories = eventHandlerFactories; |
|||
} |
|||
} |
|||
|
|||
// Reference from
|
|||
// https://blogs.msdn.microsoft.com/benwilli/2017/02/09/an-alternative-to-configureawaitfalse-everywhere/
|
|||
private struct SynchronizationContextRemover : INotifyCompletion |
|||
{ |
|||
public bool IsCompleted |
|||
{ |
|||
get { return SynchronizationContext.Current == null; } |
|||
} |
|||
|
|||
public void OnCompleted(Action continuation) |
|||
{ |
|||
var prevContext = SynchronizationContext.Current; |
|||
try |
|||
{ |
|||
SynchronizationContext.SetSynchronizationContext(null); |
|||
continuation(); |
|||
} |
|||
finally |
|||
{ |
|||
SynchronizationContext.SetSynchronizationContext(prevContext); |
|||
} |
|||
} |
|||
|
|||
public SynchronizationContextRemover GetAwaiter() |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
public void GetResult() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
using System; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus.Factories |
|||
{ |
|||
/// <summary>
|
|||
/// Defines an interface for factories those are responsible to create/get and release of event handlers.
|
|||
/// </summary>
|
|||
public interface IEventHandlerFactory |
|||
{ |
|||
/// <summary>
|
|||
/// Gets an event handler.
|
|||
/// </summary>
|
|||
/// <returns>The event handler</returns>
|
|||
IEventHandler GetHandler(); |
|||
|
|||
/// <summary>
|
|||
/// Gets type of the handler (without creating an instance).
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
Type GetHandlerType(); |
|||
|
|||
/// <summary>
|
|||
/// Releases an event handler.
|
|||
/// </summary>
|
|||
/// <param name="handler">Handle to be released</param>
|
|||
void ReleaseHandler(IEventHandler handler); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.EventBus.Factories.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// Used to unregister a <see cref="IEventHandlerFactory"/> on <see cref="Dispose"/> method.
|
|||
/// </summary>
|
|||
internal class FactoryUnregistrar : IDisposable |
|||
{ |
|||
private readonly IEventBus _eventBus; |
|||
private readonly Type _eventType; |
|||
private readonly IEventHandlerFactory _factory; |
|||
|
|||
public FactoryUnregistrar(IEventBus eventBus, Type eventType, IEventHandlerFactory factory) |
|||
{ |
|||
_eventBus = eventBus; |
|||
_eventType = eventType; |
|||
_factory = factory; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_eventBus.Unregister(_eventType, _factory); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using System; |
|||
using Volo.Abp.DynamicProxy; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus.Factories.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// This <see cref="IEventHandlerFactory"/> implementation is used to handle events
|
|||
/// by a single instance object.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This class always gets the same single instance of handler.
|
|||
/// </remarks>
|
|||
internal class SingleInstanceHandlerFactory : IEventHandlerFactory |
|||
{ |
|||
/// <summary>
|
|||
/// The event handler instance.
|
|||
/// </summary>
|
|||
public IEventHandler HandlerInstance { get; private set; } |
|||
|
|||
/// <summary>
|
|||
///
|
|||
/// </summary>
|
|||
/// <param name="handler"></param>
|
|||
public SingleInstanceHandlerFactory(IEventHandler handler) |
|||
{ |
|||
HandlerInstance = handler; |
|||
} |
|||
|
|||
public IEventHandler GetHandler() |
|||
{ |
|||
return HandlerInstance; |
|||
} |
|||
|
|||
public Type GetHandlerType() |
|||
{ |
|||
return ProxyHelper.UnProxy(HandlerInstance).GetType(); |
|||
} |
|||
|
|||
public void ReleaseHandler(IEventHandler handler) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
using System; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus.Factories.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// This <see cref="IEventHandlerFactory"/> implementation is used to handle events
|
|||
/// by a transient instance object.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This class always creates a new transient instance of handler.
|
|||
/// </remarks>
|
|||
internal class TransientEventHandlerFactory<THandler> : IEventHandlerFactory |
|||
where THandler : IEventHandler, new() |
|||
{ |
|||
/// <summary>
|
|||
/// Creates a new instance of the handler object.
|
|||
/// </summary>
|
|||
/// <returns>The handler object</returns>
|
|||
public IEventHandler GetHandler() |
|||
{ |
|||
return new THandler(); |
|||
} |
|||
|
|||
public Type GetHandlerType() |
|||
{ |
|||
return typeof(THandler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Disposes the handler object if it's <see cref="IDisposable"/>. Does nothing if it's not.
|
|||
/// </summary>
|
|||
/// <param name="handler">Handler to be released</param>
|
|||
public void ReleaseHandler(IEventHandler handler) |
|||
{ |
|||
if (handler is IDisposable) |
|||
{ |
|||
(handler as IDisposable).Dispose(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
using System; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus.Factories |
|||
{ |
|||
/// <summary>
|
|||
/// This <see cref="IEventHandlerFactory"/> implementation is used to get/release
|
|||
/// handlers using Ioc.
|
|||
/// </summary>
|
|||
public class IocHandlerFactory : IEventHandlerFactory |
|||
{ |
|||
/// <summary>
|
|||
/// Type of the handler.
|
|||
/// </summary>
|
|||
public Type HandlerType { get; } |
|||
|
|||
private readonly IServiceProvider _iocResolver; |
|||
|
|||
/// <summary>
|
|||
/// Creates a new instance of <see cref="IocHandlerFactory"/> class.
|
|||
/// </summary>
|
|||
/// <param name="iocResolver"></param>
|
|||
/// <param name="handlerType">Type of the handler</param>
|
|||
public IocHandlerFactory(IServiceProvider iocResolver, Type handlerType) |
|||
{ |
|||
_iocResolver = iocResolver; |
|||
HandlerType = handlerType; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Resolves handler object from Ioc container.
|
|||
/// </summary>
|
|||
/// <returns>Resolved handler object</returns>
|
|||
public IEventHandler GetHandler() |
|||
{ |
|||
return (IEventHandler)_iocResolver.GetRequiredService(HandlerType); |
|||
} |
|||
|
|||
public Type GetHandlerType() |
|||
{ |
|||
return HandlerType; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Releases handler object using Ioc container.
|
|||
/// </summary>
|
|||
/// <param name="handler">Handler to be released</param>
|
|||
public void ReleaseHandler(IEventHandler handler) |
|||
{ |
|||
//TODO: Scope!!!
|
|||
//_iocResolver.Release(handler);
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.EventBus.Handlers |
|||
{ |
|||
/// <summary>
|
|||
/// Defines an interface of a class that handles events asynchrounously of type <see cref="IAsyncEventHandler{TEventData}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type to handle</typeparam>
|
|||
public interface IAsyncEventHandler<in TEventData> : IEventHandler |
|||
{ |
|||
/// <summary>
|
|||
/// Handler handles the event by implementing this method.
|
|||
/// </summary>
|
|||
/// <param name="eventData">Event data</param>
|
|||
Task HandleEventAsync(TEventData eventData); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace Volo.Abp.EventBus.Handlers |
|||
{ |
|||
/// <summary>
|
|||
/// Undirect base interface for all event handlers.
|
|||
/// Implement <see cref="IEventHandler{TEventData}"/> instead of this one.
|
|||
/// </summary>
|
|||
public interface IEventHandler |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
namespace Volo.Abp.EventBus.Handlers |
|||
{ |
|||
/// <summary>
|
|||
/// Defines an interface of a class that handles events of type <see cref="IEventHandler{TEventData}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type to handle</typeparam>
|
|||
public interface IEventHandler<in TEventData> : IEventHandler |
|||
{ |
|||
/// <summary>
|
|||
/// Handler handles the event by implementing this method.
|
|||
/// </summary>
|
|||
/// <param name="eventData">Event data</param>
|
|||
void HandleEvent(TEventData eventData); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
using System; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.EventBus.Handlers.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// This event handler is an adapter to be able to use an action as <see cref="IEventHandler{TEventData}"/> implementation.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
internal class ActionEventHandler<TEventData> : |
|||
IEventHandler<TEventData>, |
|||
ITransientDependency |
|||
{ |
|||
/// <summary>
|
|||
/// Action to handle the event.
|
|||
/// </summary>
|
|||
public Action<TEventData> 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<TEventData> handler) |
|||
{ |
|||
Action = handler; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Handles the event.
|
|||
/// </summary>
|
|||
/// <param name="eventData"></param>
|
|||
public void HandleEvent(TEventData eventData) |
|||
{ |
|||
Action(eventData); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.EventBus.Handlers.Internals |
|||
{ |
|||
/// <summary>
|
|||
/// This event handler is an adapter to be able to use an action as <see cref="IAsyncEventHandler{TEventData}"/> implementation.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
internal class AsyncActionEventHandler<TEventData> : |
|||
IAsyncEventHandler<TEventData>, |
|||
ITransientDependency |
|||
{ |
|||
/// <summary>
|
|||
/// Function to handle the event.
|
|||
/// </summary>
|
|||
public Func<TEventData, Task> Action { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Creates a new instance of <see cref="AsyncActionEventHandler{TEventData}"/>.
|
|||
/// </summary>
|
|||
/// <param name="handler">Action to handle the event</param>
|
|||
public AsyncActionEventHandler(Func<TEventData, Task> handler) |
|||
{ |
|||
Action = handler; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Handles the event.
|
|||
/// </summary>
|
|||
/// <param name="eventData"></param>
|
|||
public async Task HandleEventAsync(TEventData eventData) |
|||
{ |
|||
await Action(eventData); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
public interface IDistributedEventBus |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,194 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.EventBus.Factories; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
/// <summary>
|
|||
/// Defines interface of the event bus.
|
|||
/// </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="TEventData">Event type</typeparam>
|
|||
IDisposable Register<TEventData>(Action<TEventData> action) |
|||
where TEventData : 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="TEventData">Event type</typeparam>
|
|||
IDisposable AsyncRegister<TEventData>(Func<TEventData, Task> action) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// Same (given) instance of the handler is used for all event occurrences.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="handler">Object to handle the event</param>
|
|||
IDisposable Register<TEventData>(IEventHandler<TEventData> handler) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// Same (given) instance of the async handler is used for all event occurrences.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="handler">Object to handle the event</param>
|
|||
IDisposable AsyncRegister<TEventData>(IAsyncEventHandler<TEventData> handler) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// A new instance of <see cref="THandler"/> object is created for every event occurrence.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <typeparam name="THandler">Type of the event handler</typeparam>
|
|||
IDisposable Register<TEventData, THandler>() |
|||
where TEventData : class |
|||
where THandler : IEventHandler, new(); |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// Same (given) instance of the handler is used for all event occurrences.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
/// <param name="handler">Object to handle the event</param>
|
|||
IDisposable Register(Type eventType, IEventHandler handler); |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// Given factory is used to create/release handlers
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="factory">A factory to create/release handlers</param>
|
|||
IDisposable Register<TEventData>(IEventHandlerFactory factory) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Registers to an event.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
/// <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="TEventData">Event type</typeparam>
|
|||
/// <param name="action"></param>
|
|||
void Unregister<TEventData>(Action<TEventData> action) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="action"></param>
|
|||
void AsyncUnregister<TEventData>(Func<TEventData, Task> action) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="handler">Handler object that is registered before</param>
|
|||
void Unregister<TEventData>(IEventHandler<TEventData> handler) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="handler">Handler object that is registered before</param>
|
|||
void AsyncUnregister<TEventData>(IAsyncEventHandler<TEventData> handler) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
/// <param name="handler">Handler object that is registered before</param>
|
|||
void Unregister(Type eventType, IEventHandler handler); |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="factory">Factory object that is registered before</param>
|
|||
void Unregister<TEventData>(IEventHandlerFactory factory) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters from an event.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
/// <param name="factory">Factory object that is registered before</param>
|
|||
void Unregister(Type eventType, IEventHandlerFactory factory); |
|||
|
|||
/// <summary>
|
|||
/// Unregisters all event handlers of given event type.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
void UnregisterAll<TEventData>() |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Unregisters all event handlers of given event type.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
void UnregisterAll(Type eventType); |
|||
|
|||
#endregion
|
|||
|
|||
#region Trigger
|
|||
|
|||
/// <summary>
|
|||
/// Triggers an event.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="eventData">Related data for the event</param>
|
|||
void Trigger<TEventData>(TEventData eventData) |
|||
where TEventData : 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>
|
|||
/// <typeparam name="TEventData">Event type</typeparam>
|
|||
/// <param name="eventData">Related data for the event</param>
|
|||
/// <returns>The task to handle async operation</returns>
|
|||
Task TriggerAsync<TEventData>(TEventData eventData) |
|||
where TEventData : class; |
|||
|
|||
/// <summary>
|
|||
/// Triggers an event asynchronously.
|
|||
/// </summary>
|
|||
/// <param name="eventType">Event type</param>
|
|||
/// <param name="eventData">Related data for the event</param>
|
|||
/// <returns>The task to handle async operation</returns>
|
|||
Task TriggerAsync(Type eventType, object eventData); |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
/// <summary>
|
|||
/// This interface must be implemented by event data classes that
|
|||
/// has a single generic argument and this argument will be used by inheritance.
|
|||
///
|
|||
/// For example;
|
|||
/// Assume that Student inherits From Person. When trigger an EntityCreatedEventData{Student},
|
|||
/// EntityCreatedEventData{Person} is also triggered if EntityCreatedEventData implements
|
|||
/// this interface.
|
|||
/// </summary>
|
|||
public interface IEventDataWithInheritableGenericArgument |
|||
{ |
|||
/// <summary>
|
|||
/// Gets arguments to create this class since a new instance of this class is created.
|
|||
/// </summary>
|
|||
/// <returns>Constructor arguments</returns>
|
|||
object[] GetConstructorArgs(); |
|||
} |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.EventBus.Factories; |
|||
using Volo.Abp.EventBus.Handlers; |
|||
|
|||
namespace Volo.Abp.EventBus |
|||
{ |
|||
public sealed class NullEventBus : IEventBus |
|||
{ |
|||
public static NullEventBus Instance { get; } = new NullEventBus(); |
|||
|
|||
private NullEventBus() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public IDisposable Register<TEventData>(Action<TEventData> action) where TEventData : class |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable AsyncRegister<TEventData>(Func<TEventData, Task> action) where TEventData : class |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable Register<TEventData>(IEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable AsyncRegister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable Register<TEventData, THandler>() where TEventData : class where THandler : IEventHandler, new() |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable Register(Type eventType, IEventHandler handler) |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable Register<TEventData>(IEventHandlerFactory factory) where TEventData : class |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public IDisposable Register(Type eventType, IEventHandlerFactory factory) |
|||
{ |
|||
return NullDisposable.Instance; |
|||
} |
|||
|
|||
public void Unregister<TEventData>(Action<TEventData> action) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void AsyncUnregister<TEventData>(Func<TEventData, Task> action) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Unregister<TEventData>(IEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void AsyncUnregister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Unregister(Type eventType, IEventHandler handler) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Unregister<TEventData>(IEventHandlerFactory factory) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Unregister(Type eventType, IEventHandlerFactory factory) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void UnregisterAll<TEventData>() where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void UnregisterAll(Type eventType) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Trigger<TEventData>(TEventData eventData) where TEventData : class |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void Trigger(Type eventType, object eventData) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public Task TriggerAsync<TEventData>(TEventData eventData) where TEventData : class |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task TriggerAsync(Type eventType, object eventData) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue