using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; using Volo.Abp.Json; namespace Volo.Abp.EventBus.Local { /// /// Implements EventBus as Singleton pattern. /// [ExposeServices(typeof(ILocalEventBus), typeof(LocalEventBus))] public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency { /// /// Reference to the Logger. /// public ILogger Logger { get; set; } protected AbpLocalEventBusOptions Options { get; } protected ConcurrentDictionary> HandlerFactories { get; } protected IJsonSerializer Serializer { get; } public LocalEventBus( IOptions options, IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, IEventErrorHandler errorHandler, IJsonSerializer serializer) : base(serviceScopeFactory, currentTenant, errorHandler) { Serializer = serializer; Options = options.Value; Logger = NullLogger.Instance; HandlerFactories = new ConcurrentDictionary>(); SubscribeHandlers(Options.Handlers); } /// public virtual IDisposable Subscribe(ILocalEventHandler handler) where TEvent : class { return Subscribe(typeof(TEvent), handler); } /// public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) { GetOrCreateHandlerFactories(eventType) .Locking(factories => { if (!factory.IsInFactories(factories)) { factories.Add(factory); } } ); return new EventHandlerFactoryUnregistrar(this, eventType, factory); } /// public override void Unsubscribe(Func action) { 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; if (actionHandler == null) { return false; } return actionHandler.Action == action; }); }); } /// public override void Unsubscribe(Type eventType, IEventHandler handler) { GetOrCreateHandlerFactories(eventType) .Locking(factories => { factories.RemoveAll( factory => factory is SingleInstanceHandlerFactory && (factory as SingleInstanceHandlerFactory).HandlerInstance == handler ); }); } /// public override void Unsubscribe(Type eventType, IEventHandlerFactory factory) { GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory)); } /// public override void UnsubscribeAll(Type eventType) { GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); } public override async Task PublishAsync(Type eventType, object eventData) { await PublishAsync(new LocalEventMessage(Guid.NewGuid(), eventData, eventType)); } public virtual async Task PublishAsync(LocalEventMessage localEventMessage) { var rawEventData = Serializer.Serialize(localEventMessage.EventData); await TriggerHandlersAsync(localEventMessage.EventType, localEventMessage.EventData, errorContext => { errorContext.EventData = Serializer.Deserialize(localEventMessage.EventType, rawEventData); errorContext.SetProperty(nameof(LocalEventMessage.MessageId), localEventMessage.MessageId); }); } protected override IEnumerable GetHandlerFactories(Type eventType) { var handlerFactoryList = new List(); foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))) { handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)); } return handlerFactoryList.ToArray(); } private List GetOrCreateHandlerFactories(Type eventType) { return HandlerFactories.GetOrAdd(eventType, (type) => new List()); } private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType) { //Should trigger same type if (handlerEventType == targetEventType) { return true; } //Should trigger for inherited types if (handlerEventType.IsAssignableFrom(targetEventType)) { return true; } return false; } } }