diff --git a/Examples/EventHandling/Examples.EventHandling.InMemoryEventBus/Program.cs b/Examples/EventHandling/Examples.EventHandling.InMemoryEventBus/Program.cs index f1404212..50fbeec6 100644 --- a/Examples/EventHandling/Examples.EventHandling.InMemoryEventBus/Program.cs +++ b/Examples/EventHandling/Examples.EventHandling.InMemoryEventBus/Program.cs @@ -6,6 +6,7 @@ using RCommon.EventHandling; using RCommon.EventHandling.Producers; using System.Diagnostics; +using System.Reflection; try { @@ -23,7 +24,12 @@ .WithEventHandling(eventHandling => { eventHandling.AddProducer(); - eventHandling.AddSubscriber(); + + // You can add subscribers this way which is pretty straight forward but verbose + //eventHandling.AddSubscriber(); + + // Or this way which uses a little magic but is simple + eventHandling.AddSubscribers((typeof(Program).GetTypeInfo().Assembly)); }); }).Build(); diff --git a/Src/RCommon.Core/EventHandling/EventHandlingBuilderExtensions.cs b/Src/RCommon.Core/EventHandling/EventHandlingBuilderExtensions.cs index b1a561a5..bfd1dfe6 100644 --- a/Src/RCommon.Core/EventHandling/EventHandlingBuilderExtensions.cs +++ b/Src/RCommon.Core/EventHandling/EventHandlingBuilderExtensions.cs @@ -53,19 +53,5 @@ public static void AddProducer(this IEventHandlingBuilder builder, T producer builder.Services.TryAddSingleton(service); } } - - public static void AddSubscriber(this IEventHandlingBuilder builder) - where TEvent : class, ISerializableEvent - where TEventHandler : class, ISubscriber - { - builder.Services.AddScoped, TEventHandler>(); - } - - public static void AddSubscriber(this IEventHandlingBuilder builder, Func getSubscriber) - where TEvent : class, ISerializableEvent - where TEventHandler : class, ISubscriber - { - builder.Services.TryAddScoped(getSubscriber); - } } } diff --git a/Src/RCommon.Core/EventHandling/IInMemoryEventBusBuilder.cs b/Src/RCommon.Core/EventHandling/IInMemoryEventBusBuilder.cs new file mode 100644 index 00000000..f82742ac --- /dev/null +++ b/Src/RCommon.Core/EventHandling/IInMemoryEventBusBuilder.cs @@ -0,0 +1,9 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace RCommon.EventHandling +{ + public interface IInMemoryEventBusBuilder : IEventHandlingBuilder + { + + } +} diff --git a/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilder.cs b/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilder.cs index 45dd4846..05697743 100644 --- a/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilder.cs +++ b/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilder.cs @@ -7,7 +7,7 @@ namespace RCommon.EventHandling { - public class InMemoryEventBusBuilder : IEventHandlingBuilder + public class InMemoryEventBusBuilder : IInMemoryEventBusBuilder { public InMemoryEventBusBuilder(IRCommonBuilder builder) diff --git a/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilderExtensions.cs b/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilderExtensions.cs new file mode 100644 index 00000000..af421b89 --- /dev/null +++ b/Src/RCommon.Core/EventHandling/InMemoryEventBusBuilderExtensions.cs @@ -0,0 +1,74 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using RCommon.EventHandling.Subscribers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace RCommon.EventHandling +{ + public static class InMemoryEventBusBuilderExtensions + { + public static void AddSubscriber(this IInMemoryEventBusBuilder builder) + where TEvent : class, ISerializableEvent + where TEventHandler : class, ISubscriber + { + builder.Services.AddScoped, TEventHandler>(); + } + + public static void AddSubscriber(this IInMemoryEventBusBuilder builder, Func getSubscriber) + where TEvent : class, ISerializableEvent + where TEventHandler : class, ISubscriber + { + builder.Services.TryAddScoped(getSubscriber); + } + + public static void AddSubscribers(this IInMemoryEventBusBuilder builder, params Type[] queryHandlerTypes) + { + AddSubscribers(builder, (IEnumerable)queryHandlerTypes); + } + + public static void AddSubscribers(this IInMemoryEventBusBuilder builder, Assembly fromAssembly, + Predicate predicate = null) + { + predicate = predicate ?? (t => true); + var subscribeSynchronousToTypes = fromAssembly + .GetTypes() + .Where(t => t.GetTypeInfo().GetInterfaces().Any(IsSubscriberInterface)) + .Where(t => !t.HasConstructorParameterOfType(IsSubscriberInterface)) + .Where(t => predicate(t)); + AddSubscribers(builder, subscribeSynchronousToTypes); + } + + public static void AddSubscribers(this IInMemoryEventBusBuilder builder, IEnumerable queryHandlerTypes) + { + foreach (var queryHandlerType in queryHandlerTypes) + { + var t = queryHandlerType; + if (t.GetTypeInfo().IsAbstract) continue; + var queryHandlerInterfaces = t + .GetTypeInfo() + .GetInterfaces() + .Where(IsSubscriberInterface) + .ToList(); + if (!queryHandlerInterfaces.Any()) + { + throw new ArgumentException($"Type '{t.PrettyPrint()}' is not an '{typeof(ISubscriber<>).PrettyPrint()}'"); + } + + foreach (var queryHandlerInterface in queryHandlerInterfaces) + { + builder.Services.AddTransient(queryHandlerInterface, t); + } + } + } + + private static bool IsSubscriberInterface(this Type type) + { + return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(ISubscriber<>); + } + } +}