Skip to content

Commit

Permalink
Added dynamic InMemoryEventBus Subscriber discovery to DI interface
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonmwebb-lv committed May 10, 2024
1 parent 0addb78 commit da8a29c
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using RCommon.EventHandling;
using RCommon.EventHandling.Producers;
using System.Diagnostics;
using System.Reflection;

try
{
Expand All @@ -23,7 +24,12 @@
.WithEventHandling<InMemoryEventBusBuilder>(eventHandling =>
{
eventHandling.AddProducer<PublishWithEventBusEventProducer>();
eventHandling.AddSubscriber<TestEvent, TestEventHandler>();
// You can add subscribers this way which is pretty straight forward but verbose
//eventHandling.AddSubscriber<TestEvent, TestEventHandler>();
// Or this way which uses a little magic but is simple
eventHandling.AddSubscribers((typeof(Program).GetTypeInfo().Assembly));
});
}).Build();
Expand Down
14 changes: 0 additions & 14 deletions Src/RCommon.Core/EventHandling/EventHandlingBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,5 @@ public static void AddProducer<T>(this IEventHandlingBuilder builder, T producer
builder.Services.TryAddSingleton(service);
}
}

public static void AddSubscriber<TEvent, TEventHandler>(this IEventHandlingBuilder builder)
where TEvent : class, ISerializableEvent
where TEventHandler : class, ISubscriber<TEvent>
{
builder.Services.AddScoped<ISubscriber<TEvent>, TEventHandler>();
}

public static void AddSubscriber<TEvent, TEventHandler>(this IEventHandlingBuilder builder, Func<IServiceProvider, TEventHandler> getSubscriber)
where TEvent : class, ISerializableEvent
where TEventHandler : class, ISubscriber<TEvent>
{
builder.Services.TryAddScoped(getSubscriber);
}
}
}
9 changes: 9 additions & 0 deletions Src/RCommon.Core/EventHandling/IInMemoryEventBusBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.Extensions.DependencyInjection;

namespace RCommon.EventHandling
{
public interface IInMemoryEventBusBuilder : IEventHandlingBuilder
{

}
}
2 changes: 1 addition & 1 deletion Src/RCommon.Core/EventHandling/InMemoryEventBusBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace RCommon.EventHandling
{
public class InMemoryEventBusBuilder : IEventHandlingBuilder
public class InMemoryEventBusBuilder : IInMemoryEventBusBuilder
{

public InMemoryEventBusBuilder(IRCommonBuilder builder)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<TEvent, TEventHandler>(this IInMemoryEventBusBuilder builder)
where TEvent : class, ISerializableEvent
where TEventHandler : class, ISubscriber<TEvent>
{
builder.Services.AddScoped<ISubscriber<TEvent>, TEventHandler>();
}

public static void AddSubscriber<TEvent, TEventHandler>(this IInMemoryEventBusBuilder builder, Func<IServiceProvider, TEventHandler> getSubscriber)
where TEvent : class, ISerializableEvent
where TEventHandler : class, ISubscriber<TEvent>
{
builder.Services.TryAddScoped(getSubscriber);
}

public static void AddSubscribers(this IInMemoryEventBusBuilder builder, params Type[] queryHandlerTypes)
{
AddSubscribers(builder, (IEnumerable<Type>)queryHandlerTypes);
}

public static void AddSubscribers(this IInMemoryEventBusBuilder builder, Assembly fromAssembly,
Predicate<Type> 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<Type> 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<>);
}
}
}

0 comments on commit da8a29c

Please sign in to comment.