using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Collections;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
namespace Volo.Abp.EventBus
{
public abstract class EventBusBase : IEventBus
{
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IEventErrorHandler ErrorHandler { get; }
protected EventBusBase(
IServiceScopeFactory serviceScopeFactory,
ICurrentTenant currentTenant,
IEventErrorHandler errorHandler)
{
ServiceScopeFactory = serviceScopeFactory;
CurrentTenant = currentTenant;
ErrorHandler = errorHandler;
}
///
public virtual IDisposable Subscribe(Func action) where TEvent : class
{
return Subscribe(typeof(TEvent), new ActionEventHandler(action));
}
///
public virtual IDisposable Subscribe()
where TEvent : class
where THandler : IEventHandler, new()
{
return Subscribe(typeof(TEvent), new TransientEventHandlerFactory());
}
///
public virtual IDisposable Subscribe(Type eventType, IEventHandler handler)
{
return Subscribe(eventType, new SingleInstanceHandlerFactory(handler));
}
///
public virtual IDisposable Subscribe(IEventHandlerFactory factory) where TEvent : class
{
return Subscribe(typeof(TEvent), factory);
}
public abstract IDisposable Subscribe(Type eventType, IEventHandlerFactory factory);
public abstract void Unsubscribe(Func action) where TEvent : class;
///
public virtual void Unsubscribe(ILocalEventHandler handler) where TEvent : class
{
Unsubscribe(typeof(TEvent), handler);
}
public abstract void Unsubscribe(Type eventType, IEventHandler handler);
///
public virtual void Unsubscribe(IEventHandlerFactory factory) where TEvent : class
{
Unsubscribe(typeof(TEvent), factory);
}
public abstract void Unsubscribe(Type eventType, IEventHandlerFactory factory);
///
public virtual void UnsubscribeAll() where TEvent : class
{
UnsubscribeAll(typeof(TEvent));
}
///
public abstract void UnsubscribeAll(Type eventType);
///
public virtual Task PublishAsync(TEvent eventData) where TEvent : class
{
return PublishAsync(typeof(TEvent), eventData);
}
///
public abstract Task PublishAsync(Type eventType, object eventData);
public virtual async Task TriggerHandlersAsync(Type eventType, object eventData, Action onErrorAction = null)
{
var exceptions = new List();
await TriggerHandlersAsync(eventType, eventData, exceptions);
if (exceptions.Any())
{
var context = new EventExecutionErrorContext(exceptions, eventType, this);
onErrorAction?.Invoke(context);
await ErrorHandler.HandleAsync(context);
}
}
protected virtual async Task TriggerHandlersAsync(Type eventType, object eventData , List exceptions)
{
await new SynchronizationContextRemover();
foreach (var handlerFactories in GetHandlerFactories(eventType))
{
foreach (var handlerFactory in handlerFactories.EventHandlerFactories)
{
await TriggerHandlerAsync(handlerFactory, handlerFactories.EventType, eventData, exceptions);
}
}
//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 = Activator.CreateInstance(baseEventType, constructorArgs);
await PublishAsync(baseEventType, baseEventData);
}
}
}
protected virtual void SubscribeHandlers(ITypeList handlers)
{
foreach (var handler in handlers)
{
var interfaces = handler.GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
}
var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
Subscribe(genericArgs[0], new IocEventHandlerFactory(ServiceScopeFactory, handler));
}
}
}
}
protected abstract IEnumerable GetHandlerFactories(Type eventType);
protected virtual async Task TriggerHandlerAsync(IEventHandlerFactory asyncHandlerFactory, Type eventType, object eventData, List exceptions)
{
using (var eventHandlerWrapper = asyncHandlerFactory.GetHandler())
{
try
{
var handlerType = eventHandlerWrapper.EventHandler.GetType();
using (CurrentTenant.Change(GetEventDataTenantId(eventData)))
{
if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>)))
{
var method = typeof(ILocalEventHandler<>)
.MakeGenericType(eventType)
.GetMethod(
nameof(ILocalEventHandler