| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- 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 Abp.Events.Bus.Factories;
- using Abp.Events.Bus.Factories.Internals;
- using Abp.Events.Bus.Handlers;
- using Abp.Events.Bus.Handlers.Internals;
- using Abp.Extensions;
- using Abp.Threading;
- using Abp.Threading.Extensions;
- using Castle.Core.Logging;
- namespace Abp.Events.Bus
- {
- /// <summary>
- /// Implements EventBus as Singleton pattern.
- /// </summary>
- public class EventBus : IEventBus
- {
- /// <summary>
- /// Gets the default <see cref="EventBus"/> instance.
- /// </summary>
- public static EventBus Default { get; } = new EventBus();
- /// <summary>
- /// Reference to the Logger.
- /// </summary>
- public ILogger 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="Default"/> to use Global <see cref="EventBus"/>.
- /// </summary>
- public EventBus()
- {
- _handlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>();
- Logger = NullLogger.Instance;
- }
- /// <inheritdoc/>
- public IDisposable Register<TEventData>(Action<TEventData> action) where TEventData : IEventData
- {
- return Register(typeof(TEventData), new ActionEventHandler<TEventData>(action));
- }
- /// <inheritdoc/>
- public IDisposable AsyncRegister<TEventData>(Func<TEventData, Task> action) where TEventData : IEventData
- {
- return Register(typeof(TEventData), new AsyncActionEventHandler<TEventData>(action));
- }
- /// <inheritdoc/>
- public IDisposable Register<TEventData>(IEventHandler<TEventData> handler) where TEventData : IEventData
- {
- return Register(typeof(TEventData), handler);
- }
- /// <inheritdoc/>
- public IDisposable AsyncRegister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : IEventData
- {
- return Register(typeof(TEventData), handler);
- }
- /// <inheritdoc/>
- public IDisposable Register<TEventData, THandler>()
- where TEventData : IEventData
- 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 : IEventData
- {
- 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 : IEventData
- {
- 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 : IEventData
- {
- 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 : IEventData
- {
- Unregister(typeof(TEventData), handler);
- }
- /// <inheritdoc/>
- public void AsyncUnregister<TEventData>(IAsyncEventHandler<TEventData> handler) where TEventData : IEventData
- {
- 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 : IEventData
- {
- 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 : IEventData
- {
- UnregisterAll(typeof(TEventData));
- }
- /// <inheritdoc/>
- public void UnregisterAll(Type eventType)
- {
- GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
- }
- /// <inheritdoc/>
- public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
- {
- Trigger((object)null, eventData);
- }
- /// <inheritdoc/>
- public void Trigger<TEventData>(object eventSource, TEventData eventData) where TEventData : IEventData
- {
- Trigger(typeof(TEventData), eventSource, eventData);
- }
- /// <inheritdoc/>
- public void Trigger(Type eventType, IEventData eventData)
- {
- Trigger(eventType, null, eventData);
- }
- /// <inheritdoc/>
- public void Trigger(Type eventType, object eventSource, IEventData eventData)
- {
- var exceptions = new List<Exception>();
- eventData.EventSource = eventSource;
- 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 IEventDataWithInheritableGenericArgument
- 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 = (IEventData)Activator.CreateInstance(baseEventType, constructorArgs);
- baseEventData.EventTime = eventData.EventTime;
- Trigger(baseEventType, eventData.EventSource, 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 : IEventData
- {
- return TriggerAsync((object)null, eventData);
- }
- /// <inheritdoc/>
- public Task TriggerAsync<TEventData>(object eventSource, TEventData eventData) where TEventData : IEventData
- {
- return TriggerAsync(typeof(TEventData), eventSource, eventData);
- }
- /// <inheritdoc/>
- public Task TriggerAsync(Type eventType, IEventData eventData)
- {
- return TriggerAsync(eventType, null, eventData);
- }
- /// <inheritdoc/>
- public async Task TriggerAsync(Type eventType, object eventSource, IEventData eventData)
- {
- var exceptions = new List<Exception>();
- eventData.EventSource = eventSource;
- 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 IEventDataWithInheritableGenericArgument
- 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 = (IEventData)Activator.CreateInstance(baseEventType, constructorArgs);
- baseEventData.EventTime = eventData.EventTime;
- await TriggerAsync(baseEventType, eventData.EventSource, 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, IEventData 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 object[] { 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, IEventData 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 object[] { 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()
- {
- }
- }
- }
- }
|