From c745a6b9511d9c18d9d75e26716e2e6b08ad3679 Mon Sep 17 00:00:00 2001 From: MCCshreyas Date: Sat, 3 Oct 2020 18:32:24 +0530 Subject: [PATCH] Added event publisher methods. --- .gitignore | 5 ++- src/Eventify/Event.cs | 6 +-- src/Eventify/EventPublishedContext.cs | 40 +++++++++++++++++ src/Eventify/EventPublishingContext.cs | 51 +++++++++++++++++++++ src/Eventify/Eventify.csproj | 1 + src/Eventify/EventifyServiceExtensions.cs | 3 +- src/Eventify/IEventPublisherListener.cs | 20 +++++++++ src/Eventify/InMemoryEventPublisher.cs | 54 +++++++++++++++++++---- 8 files changed, 166 insertions(+), 14 deletions(-) create mode 100644 src/Eventify/EventPublishedContext.cs create mode 100644 src/Eventify/EventPublishingContext.cs create mode 100644 src/Eventify/IEventPublisherListener.cs diff --git a/.gitignore b/.gitignore index 7b4c6af..ef993cc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ obj/ riderModule.iml /_ReSharper.Caches/ .rider/ -.idea/ \ No newline at end of file +.idea/ +/.vs/Eventify/DesignTimeBuild/.dtbcache.v2 +/.vs/Eventify/v16/TestStore/0 +/.vs/Eventify/v16 diff --git a/src/Eventify/Event.cs b/src/Eventify/Event.cs index a3ba6fb..5fdc314 100644 --- a/src/Eventify/Event.cs +++ b/src/Eventify/Event.cs @@ -8,9 +8,9 @@ namespace Eventify public abstract class Event { /// - /// when given occured. + /// when given occurred. /// - public DateTimeOffset EventOccuredAt { get; } + public DateTimeOffset EventOccurredAt { get; } /// /// Unique Event Id that represents an @@ -20,7 +20,7 @@ public abstract class Event protected Event() { EventId = Guid.NewGuid(); - EventOccuredAt = DateTimeOffset.UtcNow; + EventOccurredAt = DateTimeOffset.UtcNow; } } } \ No newline at end of file diff --git a/src/Eventify/EventPublishedContext.cs b/src/Eventify/EventPublishedContext.cs new file mode 100644 index 0000000..853ceb6 --- /dev/null +++ b/src/Eventify/EventPublishedContext.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + +namespace Eventify +{ + /// + /// Contains event information which gets passed to + /// + /// after publishing event + /// + public class EventPublishedContext : EventPublishingContext + { + /// + /// Represents the does exception occurred while publishing event or not + /// + public bool IsFaulted => EventExceptionList.Count != 0; + + /// + /// This will contain occurred exception information for further logging or processing + /// + public List EventExceptionList { get; } + + /// + /// Type of handler in which has been thrown-ed + /// + public List ExceptionHandlerTypeList { get; } + + internal EventPublishedContext(Guid eventId, string eventName, Type eventType) : base(eventId, eventName, eventType) + { + EventExceptionList = new List(); + ExceptionHandlerTypeList = new List(); + } + + internal void SetException(Exception e, Type handlerExceptionType) + { + EventExceptionList.Add(e); + ExceptionHandlerTypeList.Add(handlerExceptionType); + } + } +} \ No newline at end of file diff --git a/src/Eventify/EventPublishingContext.cs b/src/Eventify/EventPublishingContext.cs new file mode 100644 index 0000000..918ce5a --- /dev/null +++ b/src/Eventify/EventPublishingContext.cs @@ -0,0 +1,51 @@ +using System; + +namespace Eventify +{ + /// + /// Contains event information which gets passed to + /// + /// before publishing event + /// + public class EventPublishingContext + { + protected object _eventData; + + /// + /// Id of currently published + /// + public Guid EventId { get; } + + /// + /// Name of currently publishing + /// + public string EventName { get; } + + /// + /// Type of class + /// + public Type EventType { get; } + + internal EventPublishingContext(Guid eventId, string eventName, Type eventType) + { + EventId = eventId; + EventName = eventName; + EventType = eventType; + } + + public void SetEventData(T eventData) + { + _eventData = eventData; + } + + public T GetEventData() + { + return (T)_eventData; + } + + public dynamic GetEventData() + { + return _eventData; + } + } +} \ No newline at end of file diff --git a/src/Eventify/Eventify.csproj b/src/Eventify/Eventify.csproj index d229858..e01065d 100644 --- a/src/Eventify/Eventify.csproj +++ b/src/Eventify/Eventify.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Eventify/EventifyServiceExtensions.cs b/src/Eventify/EventifyServiceExtensions.cs index 48d9b7e..6fb98b8 100644 --- a/src/Eventify/EventifyServiceExtensions.cs +++ b/src/Eventify/EventifyServiceExtensions.cs @@ -13,7 +13,7 @@ public static void AddEventify(this IServiceCollection services, params Assembly { throw new Exception("Please provide at least one assembly to scan for EventHandlers"); } - + foreach (var assembly in assemblies) { var classTypes = assembly.GetTypes().Select(t => t.GetTypeInfo()).Where(t => t.IsClass && !t.IsAbstract); @@ -29,7 +29,6 @@ public static void AddEventify(this IServiceCollection services, params Assembly } } } - services.AddScoped(); } } diff --git a/src/Eventify/IEventPublisherListener.cs b/src/Eventify/IEventPublisherListener.cs new file mode 100644 index 0000000..9ff05c2 --- /dev/null +++ b/src/Eventify/IEventPublisherListener.cs @@ -0,0 +1,20 @@ +namespace Eventify +{ + /// + /// Contract for Event listeners + /// + public interface IEventPublisherListener + { + /// + /// Gets executed before publishing an + /// + /// Context containing current information + void OnEventPublishing(EventPublishingContext context); + + /// + /// Gets executed after publishing an + /// + /// Context containing event execution information + void OnEventPublished(EventPublishedContext context); + } +} \ No newline at end of file diff --git a/src/Eventify/InMemoryEventPublisher.cs b/src/Eventify/InMemoryEventPublisher.cs index a3ac14f..2ded183 100644 --- a/src/Eventify/InMemoryEventPublisher.cs +++ b/src/Eventify/InMemoryEventPublisher.cs @@ -2,35 +2,73 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace Eventify { /// - /// A event publisher that publishes event in memory + /// A event publisher that publishes event in process/memory /// public class InMemoryEventPublisher : IEventPublisher { private readonly IServiceProvider _serviceProvider; - private static readonly ConcurrentDictionary EventHandlers = new ConcurrentDictionary(); + private readonly IEnumerable _eventPublisherListener; + private readonly ConcurrentDictionary _handlersCacheDictionary = new ConcurrentDictionary(); - public InMemoryEventPublisher(IServiceProvider serviceProvider) + public InMemoryEventPublisher(IServiceProvider serviceProvider, IEnumerable eventPublisherListener) { _serviceProvider = serviceProvider; + _eventPublisherListener = eventPublisherListener; } - + public Task Publish(Event @event) { var eventHandlerType = typeof(IEventHandler<>).MakeGenericType(@event.GetType()); - var handlers = - (IEnumerable) _serviceProvider.GetService(typeof(IEnumerable<>).MakeGenericType(eventHandlerType)); + var handlers = _handlersCacheDictionary.GetOrAdd(@event.GetType(), (IEnumerable)_serviceProvider.GetService(typeof(IEnumerable<>).MakeGenericType(eventHandlerType))); + + var currentEventType = @event.GetType(); + var currentEventName = currentEventType.Name; + + var eventPublishingContext = + new EventPublishingContext(@event.EventId, currentEventName, currentEventType); + + eventPublishingContext.SetEventData(@event); + + if(_eventPublisherListener != null && _eventPublisherListener.Any()) + { + foreach (var listeners in _eventPublisherListener) + { + listeners.OnEventPublishing(eventPublishingContext); + } + } + + EventPublishedContext publishedContext = null; foreach (var handler in handlers) { - handler.GetType().GetMethod("Handle")?.Invoke(handler, new object[] {@event}); + publishedContext = + new EventPublishedContext(@event.EventId, currentEventName, currentEventType); + try + { + handler.GetType().GetMethod("Handle")?.Invoke(handler, new object[] {eventPublishingContext.GetEventData()}); + } + catch (Exception e) + { + publishedContext.SetException(e, handler.GetType()); + publishedContext.SetEventData(eventPublishingContext.GetEventData()); + } + } + + if (_eventPublisherListener != null && _eventPublisherListener.Any()) + { + foreach (var item in _eventPublisherListener) + { + item.OnEventPublished(publishedContext); + } } - + return Task.CompletedTask; } }