Browse Source

Add anonymous name-based event support

Introduce AnonymousEventData and add name-based (string) event publish/subscribe APIs across the event bus.

Key changes:
- New AnonymousEventData class with conversion helpers (ConvertToTypedObject/ConvertToTypedObject<T>/ConvertToTypedObject(Type)) and caching for JsonElement payloads.
- Extended IEventBus and IDistributedEventBus interfaces with PublishAsync(string, ...), Subscribe/Unsubscribe/UnsubscribeAll overloads that accept string event names and factories/handlers.
- DistributedEventBusBase implements name-based PublishAsync and Subscribe overloads and adapts anonymous event publishing to typed flows.
- Updated concrete distributed bus implementations (Azure, Dapr, Kafka, RabbitMQ, Rebus, Local) to support anonymous handlers, inbox/outbox processing for anonymous events, serialization helpers, and handler-factory management. Changes include deduplication when registering factories, removal helpers for single-instance handlers, and preserving EventTypes mapping (AnonymousEventData is not added to EventTypes).
- Fixed/centralized logic for mapping event names <-> event types, handler lookup (including anonymous handlers), and outbox/inbox processing so both typed and anonymous (name-based) events are handled consistently.

Compatibility: existing typed event handling is preserved; new string-based APIs allow publishing and subscribing to events identified only by name.
pull/25023/head
SALİH ÖZKARA 2 months ago
parent
commit
7672598bee
  1. 37
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/AnonymousEventData.cs
  2. 42
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IDistributedEventBus.cs
  3. 40
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/IEventBus.cs
  4. 5
      framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Local/ILocalEventBus.cs
  5. 291
      framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs
  6. 187
      framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs
  7. 67
      framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs
  8. 25
      framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs
  9. 300
      framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs
  10. 28
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs
  11. 32
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs
  12. 29
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs
  13. 15
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs
  14. 3
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerFactoryUnregistrar.cs
  15. 24
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs
  16. 22
      framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs

37
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/AnonymousEventData.cs

@ -5,25 +5,54 @@ using System.Text.Json;
namespace Volo.Abp.EventBus;
/// <summary>
/// Wraps arbitrary event data with a string-based event name for anonymous (type-less) event handling.
/// Acts as both an envelope and event type for events that are identified by name rather than CLR type.
/// </summary>
[Serializable]
public class AnonymousEventData
{
/// <summary>
/// The string-based name that identifies the event.
/// </summary>
public string EventName { get; }
/// <summary>
/// The raw event data payload. Can be a CLR object, <see cref="JsonElement"/>, or any serializable object.
/// </summary>
public object Data { get; }
private JsonElement? _cachedJsonElement;
/// <summary>
/// Creates a new instance of <see cref="AnonymousEventData"/>.
/// </summary>
/// <param name="eventName">The string-based name that identifies the event</param>
/// <param name="data">The raw event data payload</param>
public AnonymousEventData(string eventName, object data)
{
EventName = eventName;
Data = data;
}
/// <summary>
/// Converts the <see cref="Data"/> to a loosely-typed object graph
/// (dictionaries for objects, lists for arrays, primitives for values).
/// </summary>
/// <returns>A CLR object representation of the event data</returns>
public object ConvertToTypedObject()
{
return ConvertElement(GetJsonElement());
}
/// <summary>
/// Converts the <see cref="Data"/> to a strongly-typed <typeparamref name="T"/> object.
/// Returns the data directly if it is already of type <typeparamref name="T"/>,
/// otherwise deserializes from JSON.
/// </summary>
/// <typeparam name="T">Target type to convert to</typeparam>
/// <returns>The deserialized object of type <typeparamref name="T"/></returns>
/// <exception cref="InvalidOperationException">Thrown when deserialization fails</exception>
public T ConvertToTypedObject<T>()
{
if (Data is T typedData)
@ -35,6 +64,14 @@ public class AnonymousEventData
?? throw new InvalidOperationException($"Failed to deserialize AnonymousEventData to {typeof(T).FullName}.");
}
/// <summary>
/// Converts the <see cref="Data"/> to the specified <paramref name="type"/>.
/// Returns the data directly if it is already an instance of the target type,
/// otherwise deserializes from JSON.
/// </summary>
/// <param name="type">Target type to convert to</param>
/// <returns>The deserialized object</returns>
/// <exception cref="InvalidOperationException">Thrown when deserialization fails</exception>
public object ConvertToTypedObject(Type type)
{
if (type.IsInstanceOfType(Data))

42
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Distributed/IDistributedEventBus.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
namespace Volo.Abp.EventBus.Distributed;
@ -14,15 +14,55 @@ public interface IDistributedEventBus : IEventBus
IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler)
where TEvent : class;
/// <summary>
/// Triggers an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="eventData">Related data for the event</param>
/// <param name="onUnitOfWorkComplete">True, to publish the event at the end of the current unit of work, if available</param>
/// <param name="useOutbox">True, to use the outbox pattern for reliable event publishing</param>
/// <returns>The task to handle async operation</returns>
Task PublishAsync<TEvent>(
TEvent eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
where TEvent : class;
/// <summary>
/// Triggers an event.
/// </summary>
/// <param name="eventType">Event type</param>
/// <param name="eventData">Related data for the event</param>
/// <param name="onUnitOfWorkComplete">True, to publish the event at the end of the current unit of work, if available</param>
/// <param name="useOutbox">True, to use the outbox pattern for reliable event publishing</param>
/// <returns>The task to handle async operation</returns>
Task PublishAsync(
Type eventType,
object eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true);
/// <summary>
/// Registers to an event by its string-based event name.
/// Same (given) instance of the handler is used for all event occurrences.
/// Wraps the handler as <see cref="IDistributedEventHandler{AnonymousEventData}"/>.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="handler">Object to handle the event</param>
IDisposable Subscribe(string eventName, IDistributedEventHandler<AnonymousEventData> handler);
/// <summary>
/// Triggers an event by its string-based event name.
/// Used for anonymous (type-less) event publishing over distributed event bus.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="eventData">Related data for the event</param>
/// <param name="onUnitOfWorkComplete">True, to publish the event at the end of the current unit of work, if available</param>
/// <param name="useOutbox">True, to use the outbox pattern for reliable event publishing</param>
/// <returns>The task to handle async operation</returns>
Task PublishAsync(
string eventName,
object eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true);
}

40
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/IEventBus.cs

@ -24,6 +24,14 @@ public interface IEventBus
/// <returns>The task to handle async operation</returns>
Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true);
/// <summary>
/// Triggers an event by its string-based event name.
/// Used for anonymous (type-less) event publishing.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="eventData">Related data for the event</param>
/// <param name="onUnitOfWorkComplete">True, to publish the event at the end of the current unit of work, if available</param>
/// <returns>The task to handle async operation</returns>
Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true);
/// <summary>
@ -53,6 +61,20 @@ public interface IEventBus
/// <param name="handler">Object to handle the event</param>
IDisposable Subscribe(Type eventType, IEventHandler handler);
/// <summary>
/// Registers to an event by its string-based event name.
/// Same (given) instance of the handler is used for all event occurrences.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="handler">Object to handle the event</param>
IDisposable Subscribe(string eventName, IEventHandler handler);
/// <summary>
/// Registers to an event by its string-based event name.
/// Given factory is used to create/release handlers.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="handler">A factory to create/release handlers</param>
IDisposable Subscribe(string eventName, IEventHandlerFactory handler);
/// <summary>
@ -109,8 +131,20 @@ public interface IEventBus
/// <param name="factory">Factory object that is registered before</param>
void Unsubscribe(Type eventType, IEventHandlerFactory factory);
/// <summary>
/// Unregisters from an event by its string-based event name.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="factory">Factory object that is registered before</param>
void Unsubscribe(string eventName, IEventHandlerFactory factory);
/// <summary>
/// Unregisters from an event by its string-based event name.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <param name="handler">Handler object that is registered before</param>
void Unsubscribe(string eventName, IEventHandler handler);
/// <summary>
/// Unregisters all event handlers of given event type.
/// </summary>
@ -123,4 +157,10 @@ public interface IEventBus
/// </summary>
/// <param name="eventType">Event type</param>
void UnsubscribeAll(Type eventType);
/// <summary>
/// Unregisters all event handlers of given string-based event name.
/// </summary>
/// <param name="eventName">Name of the event</param>
void UnsubscribeAll(string eventName);
}

5
framework/src/Volo.Abp.EventBus.Abstractions/Volo/Abp/EventBus/Local/ILocalEventBus.cs

@ -24,5 +24,10 @@ public interface ILocalEventBus : IEventBus
/// <returns></returns>
List<EventTypeWithEventHandlerFactories> GetEventHandlerFactories(Type eventType);
/// <summary>
/// Gets the list of event handler factories for the given string-based event name.
/// </summary>
/// <param name="eventName">Name of the event</param>
/// <returns>List of event handler factories registered for the given event name</returns>
List<EventTypeWithEventHandlerFactories> GetAnonymousEventHandlerFactories(string eventName);
}

291
framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs

@ -114,100 +114,6 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
}
}
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{
await PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, outgoingEvent.GetCorrelationId(), outgoingEvent.Id);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{
var outgoingEventArray = outgoingEvents.ToArray();
var publisher = await PublisherPool.GetAsync(
Options.TopicName,
Options.ConnectionName);
using var messageBatch = await publisher.CreateMessageBatchAsync();
foreach (var outgoingEvent in outgoingEventArray)
{
var message = new ServiceBusMessage(outgoingEvent.EventData) { Subject = outgoingEvent.EventName };
if (message.MessageId.IsNullOrWhiteSpace())
{
message.MessageId = outgoingEvent.Id.ToString();
}
message.CorrelationId = outgoingEvent.GetCorrelationId();
if (!messageBatch.TryAddMessage(message))
{
throw new AbpException(
"The message is too large to fit in the batch. Set AbpEventBusBoxesOptions.OutboxWaitingEventMaxCount to reduce the number");
}
}
await publisher.SendMessagesAsync(messageBatch);
foreach (var outgoingEvent in outgoingEventArray)
{
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
}
public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(incomingEvent.EventName))
{
var element = Serializer.Deserialize<object>(incomingEvent.EventData);
eventData = new AnonymousEventData(incomingEvent.EventName, element);
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var exceptions = new List<Exception>();
using (CorrelationIdProvider.Change(incomingEvent.GetCorrelationId()))
{
await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
}
if (exceptions.Any())
{
ThrowOriginalExceptions(eventType, exceptions);
}
}
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
}
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
{
var handlerFactories = GetOrCreateHandlerFactories(eventType);
@ -221,16 +127,17 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
var handlerFactories = GetOrCreateAnonymousHandlerFactories(eventName);
if (handler.IsInFactories(handlerFactories))
{
return NullDisposable.Instance;
}
handlerFactories.Add(handler);
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
@ -281,19 +188,15 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
GetOrCreateHandlerFactories(eventType)
.Locking(factories => factories.Remove(factory));
}
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
{
GetOrCreateHandlerFactories(eventType)
.Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -323,6 +226,100 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{
await PublishAsync(outgoingEvent.EventName, outgoingEvent.EventData, outgoingEvent.GetCorrelationId(), outgoingEvent.Id);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{
var outgoingEventArray = outgoingEvents.ToArray();
var publisher = await PublisherPool.GetAsync(
Options.TopicName,
Options.ConnectionName);
using var messageBatch = await publisher.CreateMessageBatchAsync();
foreach (var outgoingEvent in outgoingEventArray)
{
var message = new ServiceBusMessage(outgoingEvent.EventData) { Subject = outgoingEvent.EventName };
if (message.MessageId.IsNullOrWhiteSpace())
{
message.MessageId = outgoingEvent.Id.ToString();
}
message.CorrelationId = outgoingEvent.GetCorrelationId();
if (!messageBatch.TryAddMessage(message))
{
throw new AbpException(
"The message is too large to fit in the batch. Set AbpEventBusBoxesOptions.OutboxWaitingEventMaxCount to reduce the number");
}
}
await publisher.SendMessagesAsync(messageBatch);
foreach (var outgoingEvent in outgoingEventArray)
{
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
}
public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(incomingEvent.EventName))
{
var element = Serializer.Deserialize<object>(incomingEvent.EventData);
eventData = new AnonymousEventData(incomingEvent.EventName, element);
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var exceptions = new List<Exception>();
using (CorrelationIdProvider.Change(incomingEvent.GetCorrelationId()))
{
await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
}
if (exceptions.Any())
{
ThrowOriginalExceptions(eventType, exceptions);
}
}
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
}
protected virtual Task PublishAsync(string eventName, object eventData)
{
var body = Serializer.Serialize(eventData);
@ -355,13 +352,44 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
await publisher.SendMessageAsync(message);
}
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
if (typeof(AnonymousEventData) != eventType)
{
EventTypes.GetOrAdd(eventName, eventType);
}
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{
return HandlerFactories.GetOrAdd(
eventType,
type =>
{
var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>();
}
);
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{
return HandlerFactories
.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))
.Select(handlerFactory =>
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value))
.ToArray();
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
var eventNames = EventTypes.Where(x => ShouldTriggerEventForHandler(eventType, x.Value)).Select(x => x.Key).ToList();
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
}
foreach (var handlerFactory in AnonymousHandlerFactories.Where(aehf => eventNames.Contains(aehf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
}
return handlerFactoryList.ToArray();
}
protected override Type? GetEventTypeByEventName(string eventName)
@ -369,6 +397,34 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return EventTypes.GetOrDefault(eventName);
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories => factories.Clear());
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
{
var result = new List<EventTypeWithEventHandlerFactories>();
@ -396,23 +452,4 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen
{
return handlerEventType == targetEventType || handlerEventType.IsAssignableFrom(targetEventType);
}
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
private List<IEventHandlerFactory> GetOrCreateHandlerFactories(Type eventType)
{
return HandlerFactories.GetOrAdd(
eventType,
type =>
{
var eventName = EventNameAttribute.GetNameOrDefault(type);
EventTypes.GetOrAdd(eventName, eventType);
return new List<IEventHandlerFactory>();
}
);
}
}

187
framework/src/Volo.Abp.EventBus.Dapr/Volo/Abp/EventBus/Dapr/DaprDistributedEventBus.cs

@ -81,6 +81,21 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
var handlerFactories = GetOrCreateAnonymousHandlerFactories(eventName);
if (handler.IsInFactories(handlerFactories))
{
return NullDisposable.Instance;
}
handlerFactories.Add(handler);
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
}
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action)
{
Check.NotNull(action, nameof(action));
@ -131,6 +146,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -143,7 +159,7 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
if (AnonymousHandlerFactories.ContainsKey(eventName))
{
return PublishAsync(typeof(AnonymousEventData), new AnonymousEventData(eventName, eventData), onUnitOfWorkComplete);
return PublishAsync(typeof(AnonymousEventData), anonymousEventData, onUnitOfWorkComplete);
}
throw new AbpException($"Unknown event name: {eventName}");
@ -160,73 +176,25 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
protected override 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();
}
protected override Type? GetEventTypeByEventName(string eventName)
{
return EventTypes.GetOrDefault(eventName);
}
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories =>
{
if (!handler.IsInFactories(factories))
{
factories.Add(handler);
}
});
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
}
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{
var result = new List<EventTypeWithEventHandlerFactories>();
var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName);
object eventData;
var eventType = GetEventTypeByEventName(eventName);
if (eventType != null)
{
result.AddRange(GetHandlerFactories(eventType));
eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType);
}
foreach (var handlerFactory in AnonymousHandlerFactories.Where(hf => hf.Key == eventName))
else if (AnonymousHandlerFactories.ContainsKey(outgoingEvent.EventName))
{
result.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
eventData = Serializer.Deserialize(outgoingEvent.EventData, typeof(object));
}
return result;
}
private List<IEventHandlerFactory> GetOrCreateAnonymousHandlerFactories(string eventName)
{
return AnonymousHandlerFactories.GetOrAdd(eventName, _ => new List<IEventHandlerFactory>());
}
public async override Task PublishFromOutboxAsync(OutgoingEventInfo outgoingEvent, OutboxConfig outboxConfig)
{
var eventType = GetEventType(outgoingEvent.EventName);
if (eventType == null)
else
{
return;
}
await PublishToDaprAsync(outgoingEvent.EventName, Serializer.Deserialize(outgoingEvent.EventData, eventType), outgoingEvent.Id, outgoingEvent.GetCorrelationId());
await PublishToDaprAsync(outgoingEvent.EventName, eventData, outgoingEvent.Id, outgoingEvent.GetCorrelationId());
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
@ -262,13 +230,23 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
public async override Task ProcessFromInboxAsync(IncomingEventInfo incomingEvent, InboxConfig inboxConfig)
{
var eventType = GetEventType(incomingEvent.EventName);
if (eventType == null)
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(incomingEvent.EventName))
{
eventData = new AnonymousEventData(incomingEvent.EventName, Serializer.Deserialize(incomingEvent.EventData, typeof(object)));
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
var exceptions = new List<Exception>();
using (CorrelationIdProvider.Change(incomingEvent.GetCorrelationId()))
{
@ -285,9 +263,24 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
return Serializer.Serialize(eventData);
}
protected virtual async Task PublishToDaprAsync(Type eventType, object eventData, Guid? messageId = null, string? correlationId = null)
{
await PublishToDaprAsync(EventNameAttribute.GetNameOrDefault(eventType), eventData, messageId, correlationId);
}
protected virtual async Task PublishToDaprAsync(string eventName, object eventData, Guid? messageId = null, string? correlationId = null)
{
var client = await DaprClientFactory.CreateAsync();
var data = new AbpDaprEventData(DaprEventBusOptions.PubSubName, eventName, (messageId ?? GuidGenerator.Create()).ToString("N"), Serializer.SerializeToString(eventData), correlationId);
await client.PublishEventAsync(pubsubName: DaprEventBusOptions.PubSubName, topicName: eventName, data: data);
}
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
if (typeof(AnonymousEventData) != eventType)
{
EventTypes.GetOrAdd(eventName, eventType);
}
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
@ -304,21 +297,81 @@ public class DaprDistributedEventBus : DistributedEventBusBase, ISingletonDepend
);
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
var eventNames = EventTypes.Where(x => ShouldTriggerEventForHandler(eventType, x.Value)).Select(x => x.Key).ToList();
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
}
foreach (var handlerFactory in AnonymousHandlerFactories.Where(aehf => eventNames.Contains(aehf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
}
return handlerFactoryList.ToArray();
}
protected override Type? GetEventTypeByEventName(string eventName)
{
return EventTypes.GetOrDefault(eventName);
}
public Type? GetEventType(string eventName)
{
return EventTypes.GetOrDefault(eventName);
}
protected virtual async Task PublishToDaprAsync(Type eventType, object eventData, Guid? messageId = null, string? correlationId = null)
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
await PublishToDaprAsync(EventNameAttribute.GetNameOrDefault(eventType), eventData, messageId, correlationId);
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
protected virtual async Task PublishToDaprAsync(string eventName, object eventData, Guid? messageId = null, string? correlationId = null)
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
var client = await DaprClientFactory.CreateAsync();
var data = new AbpDaprEventData(DaprEventBusOptions.PubSubName, eventName, (messageId ?? GuidGenerator.Create()).ToString("N"), Serializer.SerializeToString(eventData), correlationId);
await client.PublishEventAsync(pubsubName: DaprEventBusOptions.PubSubName, topicName: eventName, data: data);
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Clear());
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
{
var result = new List<EventTypeWithEventHandlerFactories>();
var eventType = GetEventTypeByEventName(eventName);
if (eventType != null)
{
result.AddRange(GetHandlerFactories(eventType));
}
foreach (var handlerFactory in AnonymousHandlerFactories.Where(hf => hf.Key == eventName))
{
result.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
}
return result;
}
private List<IEventHandlerFactory> GetOrCreateAnonymousHandlerFactories(string eventName)
{
return AnonymousHandlerFactories.GetOrAdd(eventName, _ => new List<IEventHandlerFactory>());
}
private static bool ShouldTriggerEventForHandler(Type targetEventType, Type handlerEventType)

67
framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs

@ -127,16 +127,18 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories =>
var handlerFactories = GetOrCreateAnonymousHandlerFactories(eventName);
if (handler.IsInFactories(handlerFactories))
{
if (!handler.IsInFactories(factories))
{
factories.Add(handler);
}
});
return NullDisposable.Instance;
}
handlerFactories.Add(handler);
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
}
@ -188,11 +190,6 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory));
}
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
@ -200,6 +197,7 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -212,7 +210,7 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
if (AnonymousHandlerFactories.ContainsKey(eventName))
{
return PublishAsync(typeof(AnonymousEventData), new AnonymousEventData(eventName, eventData), onUnitOfWorkComplete);
return PublishAsync(typeof(AnonymousEventData), anonymousEventData, onUnitOfWorkComplete);
}
throw new AbpException($"Unknown event name: {eventName}");
@ -392,7 +390,10 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
if (typeof(AnonymousEventData) != eventType)
{
EventTypes.GetOrAdd(eventName, eventType);
}
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
@ -412,12 +413,16 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
var eventNames = EventTypes.Where(x => ShouldTriggerEventForHandler(eventType, x.Value)).Select(x => x.Key).ToList();
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))
)
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{
handlerFactoryList.Add(
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
}
foreach (var handlerFactory in AnonymousHandlerFactories.Where(aehf => eventNames.Contains(aehf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
}
return handlerFactoryList.ToArray();
@ -428,6 +433,32 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return EventTypes.GetOrDefault(eventName);
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Clear());
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
{
var result = new List<EventTypeWithEventHandlerFactories>();

25
framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs

@ -149,7 +149,8 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
var handlerFactories = GetOrCreateAnonymousHandlerFactories(eventName);
@ -223,6 +224,7 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -482,11 +484,32 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, IRabbitMqDis
return EventTypes.GetOrDefault(eventName);
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Clear());
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
{
var result = new List<EventTypeWithEventHandlerFactories>();

300
framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs

@ -72,6 +72,23 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
SubscribeHandlers(AbpDistributedEventBusOptions.Handlers);
}
public async Task ProcessEventAsync(Type eventType, object eventData)
{
var messageId = MessageContext.Current.TransportMessage.GetMessageId();
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
var correlationId = MessageContext.Current.Headers.GetOrDefault(EventBusConsts.CorrelationIdHeaderName);
if (await AddToInboxAsync(messageId, eventName, eventType, eventData, correlationId))
{
return;
}
using (CorrelationIdProvider.Change(correlationId))
{
await TriggerHandlersDirectAsync(eventType, eventData);
}
}
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
{
var handlerFactories = GetOrCreateHandlerFactories(eventType);
@ -91,6 +108,21 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return new EventHandlerFactoryUnregistrar(this, eventType, factory);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
var handlerFactories = GetOrCreateAnonymousHandlerFactories(eventName);
if (handler.IsInFactories(handlerFactories))
{
return NullDisposable.Instance;
}
handlerFactories.Add(handler);
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
}
public override void Unsubscribe<TEvent>(Func<TEvent, Task> action)
{
Check.NotNull(action, nameof(action));
@ -145,23 +177,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
Rebus.Unsubscribe(eventType);
}
public async Task ProcessEventAsync(Type eventType, object eventData)
{
var messageId = MessageContext.Current.TransportMessage.GetMessageId();
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
var correlationId = MessageContext.Current.Headers.GetOrDefault(EventBusConsts.CorrelationIdHeaderName);
if (await AddToInboxAsync(messageId, eventName, eventType, eventData, correlationId))
{
return;
}
using (CorrelationIdProvider.Change(correlationId))
{
await TriggerHandlersDirectAsync(eventType, eventData);
}
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -174,7 +190,7 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
if (AnonymousHandlerFactories.ContainsKey(eventName))
{
return PublishAsync(typeof(AnonymousEventData), new AnonymousEventData(eventName, eventData), onUnitOfWorkComplete);
return PublishAsync(typeof(AnonymousEventData), anonymousEventData, onUnitOfWorkComplete);
}
throw new AbpException($"Unknown event name: {eventName}");
@ -190,6 +206,111 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
await PublishAsync(eventType, eventData, headersArguments: headers);
}
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
{
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
public async override Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig)
{
var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(outgoingEvent.EventName))
{
eventData = Serializer.Deserialize(outgoingEvent.EventData, typeof(object));
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var headers = new Dictionary<string, string>();
if (outgoingEvent.GetCorrelationId() != null)
{
headers.Add(EventBusConsts.CorrelationIdHeaderName, outgoingEvent.GetCorrelationId()!);
}
await PublishAsync(eventType, eventData, eventId: outgoingEvent.Id, headersArguments: headers);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent() {
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{
var outgoingEventArray = outgoingEvents.ToArray();
using (var scope = new RebusTransactionScope())
{
foreach (var outgoingEvent in outgoingEventArray)
{
await PublishFromOutboxAsync(outgoingEvent, outboxConfig);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
await scope.CompleteAsync();
}
}
public async override Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(incomingEvent.EventName))
{
eventData = new AnonymousEventData(incomingEvent.EventName, Serializer.Deserialize(incomingEvent.EventData, typeof(object)));
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var exceptions = new List<Exception>();
using (CorrelationIdProvider.Change(incomingEvent.GetCorrelationId()))
{
await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
}
if (exceptions.Any())
{
ThrowOriginalExceptions(eventType, exceptions);
}
}
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
}
protected virtual async Task PublishAsync(
Type eventType,
object eventData,
@ -211,14 +332,12 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
await Rebus.Publish(eventData, headersArguments);
}
protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord)
{
unitOfWork.AddOrReplaceDistributedEvent(eventRecord);
}
protected override Task OnAddToOutboxAsync(string eventName, Type eventType, object eventData)
{
EventTypes.GetOrAdd(eventName, eventType);
if (typeof(AnonymousEventData) != eventType)
{
EventTypes.GetOrAdd(eventName, eventType);
}
return base.OnAddToOutboxAsync(eventName, eventType, eventData);
}
@ -238,12 +357,16 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetHandlerFactories(Type eventType)
{
var handlerFactoryList = new List<EventTypeWithEventHandlerFactories>();
var eventNames = EventTypes.Where(x => ShouldTriggerEventForHandler(eventType, x.Value)).Select(x => x.Key).ToList();
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key)))
{
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
}
foreach (var handlerFactory in HandlerFactories.Where(hf => ShouldTriggerEventForHandler(eventType, hf.Key))
)
foreach (var handlerFactory in AnonymousHandlerFactories.Where(aehf => eventNames.Contains(aehf.Key)))
{
handlerFactoryList.Add(
new EventTypeWithEventHandlerFactories(handlerFactory.Key, handlerFactory.Value));
handlerFactoryList.Add(new EventTypeWithEventHandlerFactories(typeof(AnonymousEventData), handlerFactory.Value));
}
return handlerFactoryList.ToArray();
@ -254,22 +377,30 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return EventTypes.GetOrDefault(eventName);
}
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories =>
{
if (!handler.IsInFactories(factories))
{
factories.Add(handler);
}
});
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
return new AnonymousEventHandlerFactoryUnregistrar(this, eventName, handler);
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Clear());
}
protected override IEnumerable<EventTypeWithEventHandlerFactories> GetAnonymousHandlerFactories(string eventName)
@ -311,95 +442,4 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen
return false;
}
public async override Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig)
{
var eventType = EventTypes.GetOrDefault(outgoingEvent.EventName);
if (eventType == null)
{
return;
}
var eventData = Serializer.Deserialize(outgoingEvent.EventData, eventType);
var headers = new Dictionary<string, string>();
if (outgoingEvent.GetCorrelationId() != null)
{
headers.Add(EventBusConsts.CorrelationIdHeaderName, outgoingEvent.GetCorrelationId()!);
}
await PublishAsync(eventType, eventData, eventId: outgoingEvent.Id, headersArguments: headers);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent() {
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
public async override Task PublishManyFromOutboxAsync(IEnumerable<OutgoingEventInfo> outgoingEvents, OutboxConfig outboxConfig)
{
var outgoingEventArray = outgoingEvents.ToArray();
using (var scope = new RebusTransactionScope())
{
foreach (var outgoingEvent in outgoingEventArray)
{
await PublishFromOutboxAsync(outgoingEvent, outboxConfig);
using (CorrelationIdProvider.Change(outgoingEvent.GetCorrelationId()))
{
await TriggerDistributedEventSentAsync(new DistributedEventSent()
{
Source = DistributedEventSource.Outbox,
EventName = outgoingEvent.EventName,
EventData = outgoingEvent.EventData
});
}
}
await scope.CompleteAsync();
}
}
public async override Task ProcessFromInboxAsync(
IncomingEventInfo incomingEvent,
InboxConfig inboxConfig)
{
var eventType = EventTypes.GetOrDefault(incomingEvent.EventName);
object eventData;
if (eventType != null)
{
eventData = Serializer.Deserialize(incomingEvent.EventData, eventType);
}
else if (AnonymousHandlerFactories.ContainsKey(incomingEvent.EventName))
{
eventData = new AnonymousEventData(incomingEvent.EventName, Serializer.Deserialize(incomingEvent.EventData, typeof(object)));
eventType = typeof(AnonymousEventData);
}
else
{
return;
}
var exceptions = new List<Exception>();
using (CorrelationIdProvider.Change(incomingEvent.GetCorrelationId()))
{
await TriggerHandlersFromInboxAsync(eventType, eventData, exceptions, inboxConfig);
}
if (exceptions.Any())
{
ThrowOriginalExceptions(eventType, exceptions);
}
}
protected override byte[] Serialize(object eventData)
{
return Serializer.Serialize(eventData);
}
}

28
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs

@ -43,16 +43,25 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
CorrelationIdProvider = correlationIdProvider;
}
/// <inheritdoc/>
public virtual IDisposable Subscribe<TEvent>(IDistributedEventHandler<TEvent> handler) where TEvent : class
{
return Subscribe(typeof(TEvent), handler);
}
/// <inheritdoc/>
public virtual IDisposable Subscribe(string eventName, IDistributedEventHandler<AnonymousEventData> handler)
{
return Subscribe(eventName, (IEventHandler)handler);
}
/// <inheritdoc/>
public override Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true)
{
return PublishAsync(eventType, eventData, onUnitOfWorkComplete, useOutbox: true);
}
/// <inheritdoc/>
public virtual Task PublishAsync<TEvent>(
TEvent eventData,
bool onUnitOfWorkComplete = true,
@ -62,6 +71,7 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
return PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete, useOutbox);
}
/// <inheritdoc/>
public virtual async Task PublishAsync(
Type eventType,
object eventData,
@ -95,6 +105,24 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB
});
}
/// <inheritdoc/>
public virtual Task PublishAsync(
string eventName,
object eventData,
bool onUnitOfWorkComplete = true,
bool useOutbox = true)
{
var eventType = GetEventTypeByEventName(eventName);
var anonymousEventData = eventData as AnonymousEventData ?? new AnonymousEventData(eventName, eventData);
if (eventType != null)
{
return PublishAsync(eventType, anonymousEventData.ConvertToTypedObject(eventType), onUnitOfWorkComplete, useOutbox);
}
return PublishAsync(typeof(AnonymousEventData), anonymousEventData, onUnitOfWorkComplete, useOutbox);
}
public abstract Task PublishFromOutboxAsync(
OutgoingEventInfo outgoingEvent,
OutboxConfig outboxConfig

32
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs

@ -73,12 +73,14 @@ public class LocalDistributedEventBus : DistributedEventBusBase, ISingletonDepen
}
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
AnonymousEventNames.GetOrAdd(eventName, true);
return LocalEventBus.Subscribe(eventName, handler);
}
/// <inheritdoc/>
public override IDisposable Subscribe(Type eventType, IEventHandlerFactory factory)
{
var eventName = EventNameAttribute.GetNameOrDefault(eventType);
@ -101,16 +103,31 @@ public class LocalDistributedEventBus : DistributedEventBusBase, ISingletonDepen
LocalEventBus.Unsubscribe(eventType, factory);
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
LocalEventBus.Unsubscribe(eventName, factory);
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
LocalEventBus.Unsubscribe(eventName, handler);
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
{
LocalEventBus.UnsubscribeAll(eventType);
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
LocalEventBus.UnsubscribeAll(eventName);
}
/// <inheritdoc/>
public async override Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true)
{
if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null)
@ -147,24 +164,29 @@ public class LocalDistributedEventBus : DistributedEventBusBase, ISingletonDepen
await PublishToEventBusAsync(eventType, eventData);
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
return PublishAsync(eventName, eventData, onUnitOfWorkComplete, useOutbox: true);
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
var anonymousEventData = eventData as AnonymousEventData ?? new AnonymousEventData(eventName, eventData);
if (eventType != null)
{
return PublishAsync(eventType, anonymousEventData.ConvertToTypedObject(eventType), onUnitOfWorkComplete);
return PublishAsync(eventType, anonymousEventData.ConvertToTypedObject(eventType), onUnitOfWorkComplete, useOutbox);
}
var isAnonymous = AnonymousEventNames.ContainsKey(eventName);
if (!isAnonymous)
if (!AnonymousEventNames.ContainsKey(eventName))
{
throw new AbpException($"Unknown event name: {eventName}");
}
return PublishAsync(typeof(AnonymousEventData), new AnonymousEventData(eventName, eventData), onUnitOfWorkComplete);
return PublishAsync(typeof(AnonymousEventData), anonymousEventData, onUnitOfWorkComplete, useOutbox);
}
protected async override Task PublishToEventBusAsync(Type eventType, object eventData)

29
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs

@ -12,6 +12,7 @@ public sealed class NullDistributedEventBus : IDistributedEventBus
}
/// <inheritdoc/>
public Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
return Task.CompletedTask;
@ -37,11 +38,24 @@ public sealed class NullDistributedEventBus : IDistributedEventBus
return NullDisposable.Instance;
}
/// <inheritdoc/>
public IDisposable Subscribe(string eventName, IEventHandler handler)
{
return NullDisposable.Instance;
}
/// <inheritdoc/>
public IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
return NullDisposable.Instance;
}
/// <inheritdoc/>
public IDisposable Subscribe(string eventName, IDistributedEventHandler<AnonymousEventData> handler)
{
return NullDisposable.Instance;
}
public IDisposable Subscribe<TEvent>(IEventHandlerFactory factory) where TEvent : class
{
return NullDisposable.Instance;
@ -77,9 +91,14 @@ public sealed class NullDistributedEventBus : IDistributedEventBus
}
/// <inheritdoc/>
public void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
}
/// <inheritdoc/>
public void Unsubscribe(string eventName, IEventHandler handler)
{
}
public void UnsubscribeAll<TEvent>() where TEvent : class
@ -89,7 +108,11 @@ public sealed class NullDistributedEventBus : IDistributedEventBus
public void UnsubscribeAll(Type eventType)
{
}
/// <inheritdoc/>
public void UnsubscribeAll(string eventName)
{
}
public Task PublishAsync<TEvent>(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class
@ -111,4 +134,10 @@ public sealed class NullDistributedEventBus : IDistributedEventBus
{
return Task.CompletedTask;
}
/// <inheritdoc/>
public Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true)
{
return Task.CompletedTask;
}
}

15
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs

@ -57,6 +57,13 @@ public abstract class EventBusBase : IEventBus
return Subscribe(eventType, new SingleInstanceHandlerFactory(handler));
}
/// <inheritdoc/>
public virtual IDisposable Subscribe(string eventName, IEventHandler handler)
{
return Subscribe(eventName, new SingleInstanceHandlerFactory(handler));
}
/// <inheritdoc/>
public abstract IDisposable Subscribe(string eventName, IEventHandlerFactory handler);
/// <inheritdoc/>
@ -85,8 +92,12 @@ public abstract class EventBusBase : IEventBus
public abstract void Unsubscribe(Type eventType, IEventHandlerFactory factory);
/// <inheritdoc/>
public abstract void Unsubscribe(string eventName, IEventHandlerFactory factory);
/// <inheritdoc/>
public abstract void Unsubscribe(string eventName, IEventHandler handler);
/// <inheritdoc/>
public virtual void UnsubscribeAll<TEvent>() where TEvent : class
{
@ -96,6 +107,9 @@ public abstract class EventBusBase : IEventBus
/// <inheritdoc/>
public abstract void UnsubscribeAll(Type eventType);
/// <inheritdoc/>
public abstract void UnsubscribeAll(string eventName);
/// <inheritdoc/>
public Task PublishAsync<TEvent>(TEvent eventData, bool onUnitOfWorkComplete = true)
where TEvent : class
@ -121,6 +135,7 @@ public abstract class EventBusBase : IEventBus
await PublishToEventBusAsync(eventType, eventData);
}
/// <inheritdoc/>
public abstract Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true);
protected abstract Task PublishToEventBusAsync(Type eventType, object eventData);

3
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerFactoryUnregistrar.cs

@ -24,6 +24,9 @@ public class EventHandlerFactoryUnregistrar : IDisposable
}
}
/// <summary>
/// Used to unregister an <see cref="IEventHandlerFactory"/> for a string-based event name on <see cref="IDisposable.Dispose"/> method.
/// </summary>
public class AnonymousEventHandlerFactoryUnregistrar : IDisposable
{
private readonly IEventBus _eventBus;

24
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs

@ -57,6 +57,7 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency
return Subscribe(typeof(TEvent), handler);
}
/// <inheritdoc/>
public override IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories =>
@ -136,17 +137,39 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Remove(factory));
}
/// <inheritdoc/>
public override void Unsubscribe(string eventName, IEventHandler handler)
{
GetOrCreateAnonymousHandlerFactories(eventName)
.Locking(factories =>
{
factories.RemoveAll(
factory =>
factory is SingleInstanceHandlerFactory singleFactory &&
singleFactory.HandlerInstance == handler
);
});
}
/// <inheritdoc/>
public override void UnsubscribeAll(Type eventType)
{
GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override void UnsubscribeAll(string eventName)
{
GetOrCreateAnonymousHandlerFactories(eventName).Locking(factories => factories.Clear());
}
/// <inheritdoc/>
public override Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
var eventType = EventTypes.GetOrDefault(eventName);
@ -187,6 +210,7 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency
return GetHandlerFactories(eventType).ToList();
}
/// <inheritdoc/>
public virtual List<EventTypeWithEventHandlerFactories> GetAnonymousEventHandlerFactories(string eventName)
{
return GetAnonymousHandlerFactories(eventName).ToList();

22
framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -13,6 +13,7 @@ public sealed class NullLocalEventBus : ILocalEventBus
}
/// <inheritdoc/>
public Task PublishAsync(string eventName, object eventData, bool onUnitOfWorkComplete = true)
{
return Task.CompletedTask;
@ -33,6 +34,7 @@ public sealed class NullLocalEventBus : ILocalEventBus
return new List<EventTypeWithEventHandlerFactories>();
}
/// <inheritdoc/>
public List<EventTypeWithEventHandlerFactories> GetAnonymousEventHandlerFactories(string eventName)
{
return new List<EventTypeWithEventHandlerFactories>();
@ -48,6 +50,13 @@ public sealed class NullLocalEventBus : ILocalEventBus
return NullDisposable.Instance;
}
/// <inheritdoc/>
public IDisposable Subscribe(string eventName, IEventHandler handler)
{
return NullDisposable.Instance;
}
/// <inheritdoc/>
public IDisposable Subscribe(string eventName, IEventHandlerFactory handler)
{
return NullDisposable.Instance;
@ -88,9 +97,14 @@ public sealed class NullLocalEventBus : ILocalEventBus
}
/// <inheritdoc/>
public void Unsubscribe(string eventName, IEventHandlerFactory factory)
{
}
/// <inheritdoc/>
public void Unsubscribe(string eventName, IEventHandler handler)
{
}
public void UnsubscribeAll<TEvent>() where TEvent : class
@ -100,7 +114,11 @@ public sealed class NullLocalEventBus : ILocalEventBus
public void UnsubscribeAll(Type eventType)
{
}
/// <inheritdoc/>
public void UnsubscribeAll(string eventName)
{
}
public Task PublishAsync<TEvent>(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class

Loading…
Cancel
Save