|
|
|
@ -16,225 +16,290 @@ using Volo.Abp.Threading; |
|
|
|
using Volo.Abp.Timing; |
|
|
|
using Volo.Abp.Uow; |
|
|
|
|
|
|
|
namespace Volo.Abp.EventBus.RabbitMq; |
|
|
|
|
|
|
|
/* TODO: How to handle unsubscribe to unbind on RabbitMq (may not be possible for) |
|
|
|
*/ |
|
|
|
[Dependency(ReplaceServices = true)] |
|
|
|
[ExposeServices(typeof(IDistributedEventBus), typeof(RabbitMqDistributedEventBus))] |
|
|
|
public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDependency |
|
|
|
namespace Volo.Abp.EventBus.RabbitMq |
|
|
|
{ |
|
|
|
protected AbpRabbitMqEventBusOptions AbpRabbitMqEventBusOptions { get; } |
|
|
|
protected IConnectionPool ConnectionPool { get; } |
|
|
|
protected IRabbitMqSerializer Serializer { get; } |
|
|
|
|
|
|
|
//TODO: Accessing to the List<IEventHandlerFactory> may not be thread-safe!
|
|
|
|
protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; } |
|
|
|
protected ConcurrentDictionary<string, Type> EventTypes { get; } |
|
|
|
protected IRabbitMqMessageConsumerFactory MessageConsumerFactory { get; } |
|
|
|
protected IRabbitMqMessageConsumer Consumer { get; private set; } |
|
|
|
|
|
|
|
public RabbitMqDistributedEventBus( |
|
|
|
IOptions<AbpRabbitMqEventBusOptions> options, |
|
|
|
IConnectionPool connectionPool, |
|
|
|
IRabbitMqSerializer serializer, |
|
|
|
IServiceScopeFactory serviceScopeFactory, |
|
|
|
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions, |
|
|
|
IRabbitMqMessageConsumerFactory messageConsumerFactory, |
|
|
|
ICurrentTenant currentTenant, |
|
|
|
IUnitOfWorkManager unitOfWorkManager, |
|
|
|
IGuidGenerator guidGenerator, |
|
|
|
IClock clock) |
|
|
|
: base( |
|
|
|
serviceScopeFactory, |
|
|
|
currentTenant, |
|
|
|
unitOfWorkManager, |
|
|
|
distributedEventBusOptions, |
|
|
|
guidGenerator, |
|
|
|
clock) |
|
|
|
/* TODO: How to handle unsubscribe to unbind on RabbitMq (may not be possible for) |
|
|
|
*/ |
|
|
|
[Dependency(ReplaceServices = true)] |
|
|
|
[ExposeServices(typeof(IDistributedEventBus), typeof(RabbitMqDistributedEventBus))] |
|
|
|
public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDependency |
|
|
|
{ |
|
|
|
ConnectionPool = connectionPool; |
|
|
|
Serializer = serializer; |
|
|
|
MessageConsumerFactory = messageConsumerFactory; |
|
|
|
AbpRabbitMqEventBusOptions = options.Value; |
|
|
|
|
|
|
|
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); |
|
|
|
EventTypes = new ConcurrentDictionary<string, Type>(); |
|
|
|
} |
|
|
|
protected AbpRabbitMqEventBusOptions AbpRabbitMqEventBusOptions { get; } |
|
|
|
protected IConnectionPool ConnectionPool { get; } |
|
|
|
protected IRabbitMqSerializer Serializer { get; } |
|
|
|
|
|
|
|
//TODO: Accessing to the List<IEventHandlerFactory> may not be thread-safe!
|
|
|
|
protected ConcurrentDictionary<Type, List<IEventHandlerFactory>> HandlerFactories { get; } |
|
|
|
protected ConcurrentDictionary<string, Type> EventTypes { get; } |
|
|
|
protected IRabbitMqMessageConsumerFactory MessageConsumerFactory { get; } |
|
|
|
protected IRabbitMqMessageConsumer Consumer { get; private set; } |
|
|
|
|
|
|
|
public RabbitMqDistributedEventBus( |
|
|
|
IOptions<AbpRabbitMqEventBusOptions> options, |
|
|
|
IConnectionPool connectionPool, |
|
|
|
IRabbitMqSerializer serializer, |
|
|
|
IServiceScopeFactory serviceScopeFactory, |
|
|
|
IOptions<AbpDistributedEventBusOptions> distributedEventBusOptions, |
|
|
|
IRabbitMqMessageConsumerFactory messageConsumerFactory, |
|
|
|
ICurrentTenant currentTenant, |
|
|
|
IUnitOfWorkManager unitOfWorkManager, |
|
|
|
IGuidGenerator guidGenerator, |
|
|
|
IClock clock) |
|
|
|
: base( |
|
|
|
serviceScopeFactory, |
|
|
|
currentTenant, |
|
|
|
unitOfWorkManager, |
|
|
|
distributedEventBusOptions, |
|
|
|
guidGenerator, |
|
|
|
clock) |
|
|
|
{ |
|
|
|
ConnectionPool = connectionPool; |
|
|
|
Serializer = serializer; |
|
|
|
MessageConsumerFactory = messageConsumerFactory; |
|
|
|
AbpRabbitMqEventBusOptions = options.Value; |
|
|
|
|
|
|
|
public void Initialize() |
|
|
|
{ |
|
|
|
Consumer = MessageConsumerFactory.Create( |
|
|
|
new ExchangeDeclareConfiguration( |
|
|
|
AbpRabbitMqEventBusOptions.ExchangeName, |
|
|
|
type: "direct", |
|
|
|
durable: true |
|
|
|
), |
|
|
|
new QueueDeclareConfiguration( |
|
|
|
AbpRabbitMqEventBusOptions.ClientName, |
|
|
|
durable: true, |
|
|
|
exclusive: false, |
|
|
|
autoDelete: false |
|
|
|
), |
|
|
|
AbpRabbitMqEventBusOptions.ConnectionName |
|
|
|
); |
|
|
|
|
|
|
|
Consumer.OnMessageReceived(ProcessEventAsync); |
|
|
|
|
|
|
|
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers); |
|
|
|
} |
|
|
|
HandlerFactories = new ConcurrentDictionary<Type, List<IEventHandlerFactory>>(); |
|
|
|
EventTypes = new ConcurrentDictionary<string, Type>(); |
|
|
|
} |
|
|
|
|
|
|
|
private async Task ProcessEventAsync(IModel channel, BasicDeliverEventArgs ea) |
|
|
|
{ |
|
|
|
var eventName = ea.RoutingKey; |
|
|
|
var eventType = EventTypes.GetOrDefault(eventName); |
|
|
|
if (eventType == null) |
|
|
|
public void Initialize() |
|
|
|
{ |
|
|
|
return; |
|
|
|
Consumer = MessageConsumerFactory.Create( |
|
|
|
new ExchangeDeclareConfiguration( |
|
|
|
AbpRabbitMqEventBusOptions.ExchangeName, |
|
|
|
type: "direct", |
|
|
|
durable: true |
|
|
|
), |
|
|
|
new QueueDeclareConfiguration( |
|
|
|
AbpRabbitMqEventBusOptions.ClientName, |
|
|
|
durable: true, |
|
|
|
exclusive: false, |
|
|
|
autoDelete: false |
|
|
|
), |
|
|
|
AbpRabbitMqEventBusOptions.ConnectionName |
|
|
|
); |
|
|
|
|
|
|
|
Consumer.OnMessageReceived(ProcessEventAsync); |
|
|
|
|
|
|
|
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers); |
|
|
|
} |
|
|
|
|
|
|
|
var eventBytes = ea.Body.ToArray(); |
|
|
|
private async Task ProcessEventAsync(IModel channel, BasicDeliverEventArgs ea) |
|
|
|
{ |
|
|
|
var eventName = ea.RoutingKey; |
|
|
|
var eventType = EventTypes.GetOrDefault(eventName); |
|
|
|
if (eventType == null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var eventBytes = ea.Body.ToArray(); |
|
|
|
|
|
|
|
if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes)) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var eventData = Serializer.Deserialize(eventBytes, eventType); |
|
|
|
|
|
|
|
await TriggerHandlersAsync(eventType, eventData); |
|
|
|
} |
|
|
|
|
|
|
|
if (await AddToInboxAsync(ea.BasicProperties.MessageId, eventName, eventType, eventBytes)) |
|
|
|
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) |
|
|
|
{ |
|
|
|
return; |
|
|
|
var handlerFactories = GetOrCreateHandlerFactories(eventType); |
|
|
|
|
|
|
|
if (factory.IsInFactories(handlerFactories)) |
|
|
|
{ |
|
|
|
return NullDisposable.Instance; |
|
|
|
} |
|
|
|
|
|
|
|
handlerFactories.Add(factory); |
|
|
|
|
|
|
|
if (handlerFactories.Count == 1) //TODO: Multi-threading!
|
|
|
|
{ |
|
|
|
Consumer.BindAsync(EventNameAttribute.GetNameOrDefault(eventType)); |
|
|
|
} |
|
|
|
|
|
|
|
return new EventHandlerFactoryUnregistrar(this, eventType, factory); |
|
|
|
} |
|
|
|
|
|
|
|
var eventData = Serializer.Deserialize(eventBytes, eventType); |
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action) |
|
|
|
{ |
|
|
|
Check.NotNull(action, nameof(action)); |
|
|
|
|
|
|
|
await TriggerHandlersAsync(eventType, eventData); |
|
|
|
} |
|
|
|
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; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory) |
|
|
|
{ |
|
|
|
var handlerFactories = GetOrCreateHandlerFactories(eventType); |
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe(Type eventType, IEventHandler handler) |
|
|
|
{ |
|
|
|
GetOrCreateHandlerFactories(eventType) |
|
|
|
.Locking(factories => |
|
|
|
{ |
|
|
|
factories.RemoveAll( |
|
|
|
factory => |
|
|
|
factory is SingleInstanceHandlerFactory && |
|
|
|
(factory as SingleInstanceHandlerFactory).HandlerInstance == handler |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
if (factory.IsInFactories(handlerFactories)) |
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe(Type eventType, IEventHandlerFactory factory) |
|
|
|
{ |
|
|
|
return NullDisposable.Instance; |
|
|
|
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory)); |
|
|
|
} |
|
|
|
|
|
|
|
handlerFactories.Add(factory); |
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void UnsubscribeAll(Type eventType) |
|
|
|
{ |
|
|
|
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); |
|
|
|
} |
|
|
|
|
|
|
|
if (handlerFactories.Count == 1) //TODO: Multi-threading!
|
|
|
|
protected async override Task PublishToEventBusAsync(Type eventType, object eventData) |
|
|
|
{ |
|
|
|
Consumer.BindAsync(EventNameAttribute.GetNameOrDefault(eventType)); |
|
|
|
await PublishAsync(eventType, eventData, null); |
|
|
|
} |
|
|
|
|
|
|
|
return new EventHandlerFactoryUnregistrar(this, eventType, factory); |
|
|
|
} |
|
|
|
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) |
|
|
|
{ |
|
|
|
unitOfWork.AddOrReplaceDistributedEvent(eventRecord); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action) |
|
|
|
{ |
|
|
|
Check.NotNull(action, nameof(action)); |
|
|
|
public override Task PublishFromOutboxAsync( |
|
|
|
OutgoingEventInfo outgoingEvent, |
|
|
|
OutboxConfig outboxConfig) |
|
|
|
{ |
|
|
|
return PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id); |
|
|
|
} |
|
|
|
|
|
|
|
GetOrCreateHandlerFactories(typeof(TEvent)) |
|
|
|
.Locking(factories => |
|
|
|
public async override Task<MultipleOutgoingEventPublishResult> PublishManyFromOutboxAsync( |
|
|
|
IEnumerable<OutgoingEventInfo> outgoingEvents, |
|
|
|
OutboxConfig outboxConfig) |
|
|
|
{ |
|
|
|
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) |
|
|
|
{ |
|
|
|
factories.RemoveAll( |
|
|
|
factory => |
|
|
|
var outgoingEventArray = outgoingEvents.ToArray(); |
|
|
|
channel.ConfirmSelect(); |
|
|
|
|
|
|
|
var pendingConfirms = new ConcurrentDictionary<ulong, Guid>(); |
|
|
|
var failures = new ConcurrentBag<Guid>(); |
|
|
|
|
|
|
|
void CleanPendingConfirms(ulong sequenceNumber, bool multiple, bool ack) |
|
|
|
{ |
|
|
|
if (multiple) |
|
|
|
{ |
|
|
|
var singleInstanceFactory = factory as SingleInstanceHandlerFactory; |
|
|
|
if (singleInstanceFactory == null) |
|
|
|
var confirmed = pendingConfirms.Where(x => x.Key <= sequenceNumber); |
|
|
|
foreach (var entry in confirmed) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
pendingConfirms.TryRemove(entry.Key, out var eventId); |
|
|
|
|
|
|
|
if (!ack) |
|
|
|
{ |
|
|
|
failures.Add(eventId); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
pendingConfirms.TryRemove(sequenceNumber, out var eventId); |
|
|
|
|
|
|
|
var actionHandler = singleInstanceFactory.HandlerInstance as ActionEventHandler<TEvent>; |
|
|
|
if (actionHandler == null) |
|
|
|
if (!ack) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
failures.Add(eventId); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return actionHandler.Action == action; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
foreach (var outgoingEvent in outgoingEventArray) |
|
|
|
{ |
|
|
|
pendingConfirms.TryAdd(channel.NextPublishSeqNo, outgoingEvent.Id); |
|
|
|
await PublishInternalAsync(channel, outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe(Type eventType, IEventHandler handler) |
|
|
|
{ |
|
|
|
GetOrCreateHandlerFactories(eventType) |
|
|
|
.Locking(factories => |
|
|
|
{ |
|
|
|
factories.RemoveAll( |
|
|
|
factory => |
|
|
|
factory is SingleInstanceHandlerFactory && |
|
|
|
(factory as SingleInstanceHandlerFactory).HandlerInstance == handler |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
channel.BasicAcks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, true); |
|
|
|
channel.BasicNacks += (_, ea) => CleanPendingConfirms(ea.DeliveryTag, ea.Multiple, false); |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Unsubscribe(Type eventType, IEventHandlerFactory factory) |
|
|
|
{ |
|
|
|
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void UnsubscribeAll(Type eventType) |
|
|
|
{ |
|
|
|
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); |
|
|
|
} |
|
|
|
channel.WaitForConfirms(); |
|
|
|
|
|
|
|
protected override async Task PublishToEventBusAsync(Type eventType, object eventData) |
|
|
|
{ |
|
|
|
await PublishAsync(eventType, eventData, null); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) |
|
|
|
{ |
|
|
|
unitOfWork.AddOrReplaceDistributedEvent(eventRecord); |
|
|
|
} |
|
|
|
|
|
|
|
public override Task PublishFromOutboxAsync( |
|
|
|
OutgoingEventInfo outgoingEvent, |
|
|
|
OutboxConfig outboxConfig) |
|
|
|
{ |
|
|
|
return PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, null, eventId: outgoingEvent.Id); |
|
|
|
} |
|
|
|
return new MultipleOutgoingEventPublishResult(outgoingEventArray.Where(x => !failures.Contains(x.Id)).ToList()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public override async Task ProcessFromInboxAsync( |
|
|
|
IncomingEventInfo incomingEvent, |
|
|
|
InboxConfig inboxConfig) |
|
|
|
{ |
|
|
|
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName); |
|
|
|
if (eventType == null) |
|
|
|
public async override Task ProcessFromInboxAsync( |
|
|
|
IncomingEventInfo incomingEvent, |
|
|
|
InboxConfig inboxConfig) |
|
|
|
{ |
|
|
|
return; |
|
|
|
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName); |
|
|
|
if (eventType == null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); |
|
|
|
var exceptions = new List<Exception>(); |
|
|
|
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); |
|
|
|
if (exceptions.Any()) |
|
|
|
{ |
|
|
|
ThrowOriginalExceptions(eventType, exceptions); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType); |
|
|
|
var exceptions = new List<Exception>(); |
|
|
|
await TriggerHandlersAsync(eventType, eventData, exceptions, inboxConfig); |
|
|
|
if (exceptions.Any()) |
|
|
|
protected override byte[] Serialize(object eventData) |
|
|
|
{ |
|
|
|
ThrowOriginalExceptions(eventType, exceptions); |
|
|
|
return Serializer.Serialize(eventData); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected override byte[] Serialize(object eventData) |
|
|
|
{ |
|
|
|
return Serializer.Serialize(eventData); |
|
|
|
} |
|
|
|
public virtual Task PublishAsync(Type eventType, object eventData, IBasicProperties properties, Dictionary<string, object> headersArguments = null) |
|
|
|
{ |
|
|
|
var eventName = EventNameAttribute.GetNameOrDefault(eventType); |
|
|
|
var body = Serializer.Serialize(eventData); |
|
|
|
|
|
|
|
public Task PublishAsync(Type eventType, object eventData, IBasicProperties properties, Dictionary<string, object> headersArguments = null) |
|
|
|
{ |
|
|
|
var eventName = EventNameAttribute.GetNameOrDefault(eventType); |
|
|
|
var body = Serializer.Serialize(eventData); |
|
|
|
return PublishAsync(eventName, body, properties, headersArguments); |
|
|
|
} |
|
|
|
|
|
|
|
return PublishAsync(eventName, body, properties, headersArguments); |
|
|
|
} |
|
|
|
protected virtual Task PublishAsync( |
|
|
|
string eventName, |
|
|
|
byte[] body, |
|
|
|
IBasicProperties properties, |
|
|
|
Dictionary<string, object> headersArguments = null, |
|
|
|
Guid? eventId = null) |
|
|
|
{ |
|
|
|
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) |
|
|
|
{ |
|
|
|
return PublishInternalAsync(channel, eventName, body, properties, headersArguments, eventId); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected Task PublishAsync( |
|
|
|
string eventName, |
|
|
|
byte[] body, |
|
|
|
IBasicProperties properties, |
|
|
|
Dictionary<string, object> headersArguments = null, |
|
|
|
Guid? eventId = null) |
|
|
|
{ |
|
|
|
using (var channel = ConnectionPool.Get(AbpRabbitMqEventBusOptions.ConnectionName).CreateModel()) |
|
|
|
protected virtual Task PublishInternalAsync( |
|
|
|
IModel channel, |
|
|
|
string eventName, |
|
|
|
byte[] body, |
|
|
|
IBasicProperties properties, |
|
|
|
Dictionary<string, object> headersArguments = null, |
|
|
|
Guid? eventId = null) |
|
|
|
{ |
|
|
|
channel.ExchangeDeclare( |
|
|
|
AbpRabbitMqEventBusOptions.ExchangeName, |
|
|
|
@ -262,68 +327,68 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe |
|
|
|
basicProperties: properties, |
|
|
|
body: body |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
return Task.CompletedTask; |
|
|
|
} |
|
|
|
|
|
|
|
private void SetEventMessageHeaders(IBasicProperties properties, Dictionary<string, object> headersArguments) |
|
|
|
{ |
|
|
|
if (headersArguments == null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
return Task.CompletedTask; |
|
|
|
} |
|
|
|
|
|
|
|
properties.Headers ??= new Dictionary<string, object>(); |
|
|
|
|
|
|
|
foreach (var header in headersArguments) |
|
|
|
private void SetEventMessageHeaders(IBasicProperties properties, Dictionary<string, object> headersArguments) |
|
|
|
{ |
|
|
|
properties.Headers[header.Key] = header.Value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) |
|
|
|
{ |
|
|
|
return HandlerFactories.GetOrAdd( |
|
|
|
eventType, |
|
|
|
type => |
|
|
|
if (headersArguments == null) |
|
|
|
{ |
|
|
|
var eventName = EventNameAttribute.GetNameOrDefault(type); |
|
|
|
EventTypes[eventName] = type; |
|
|
|
return new List<IEventHandlerFactory>(); |
|
|
|
return; |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType) |
|
|
|
{ |
|
|
|
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>(); |
|
|
|
properties.Headers ??= new Dictionary<string, object>(); |
|
|
|
|
|
|
|
foreach (var handlerFactory in |
|
|
|
HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))) |
|
|
|
{ |
|
|
|
handlerFactoryList.Add( |
|
|
|
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value)); |
|
|
|
foreach (var header in headersArguments) |
|
|
|
{ |
|
|
|
properties.Headers[header.Key] = header.Value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return handlerFactoryList.ToArray(); |
|
|
|
} |
|
|
|
|
|
|
|
private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType) |
|
|
|
{ |
|
|
|
//Should trigger same type
|
|
|
|
if (handlerEventType == targetEventType) |
|
|
|
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
return HandlerFactories.GetOrAdd( |
|
|
|
eventType, |
|
|
|
type => |
|
|
|
{ |
|
|
|
var eventName = EventNameAttribute.GetNameOrDefault(type); |
|
|
|
EventTypes[eventName] = type; |
|
|
|
return new List<IEventHandlerFactory>(); |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
//TODO: Support inheritance? But it does not support on subscription to RabbitMq!
|
|
|
|
//Should trigger for inherited types
|
|
|
|
if (handlerEventType.IsAssignableFrom(targetEventType)) |
|
|
|
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
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(); |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType) |
|
|
|
{ |
|
|
|
//Should trigger same type
|
|
|
|
if (handlerEventType == targetEventType) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
//TODO: Support inheritance? But it does not support on subscription to RabbitMq!
|
|
|
|
//Should trigger for inherited types
|
|
|
|
if (handlerEventType.IsAssignableFrom(targetEventType)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|