diff --git a/src/Cortex.Mediator/Cortex.Mediator.csproj b/src/Cortex.Mediator/Cortex.Mediator.csproj
index b9e165b..e0e6275 100644
--- a/src/Cortex.Mediator/Cortex.Mediator.csproj
+++ b/src/Cortex.Mediator/Cortex.Mediator.csproj
@@ -67,6 +67,5 @@
-
diff --git a/src/Cortex.Mediator/DependencyInjection/ServiceCollectionExtensions.cs b/src/Cortex.Mediator/DependencyInjection/ServiceCollectionExtensions.cs
index 4ebde1c..60e0c06 100644
--- a/src/Cortex.Mediator/DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/Cortex.Mediator/DependencyInjection/ServiceCollectionExtensions.cs
@@ -7,8 +7,8 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
-using System.Data;
using System.Linq;
+using System.Reflection;
namespace Cortex.Mediator.DependencyInjection
{
@@ -43,43 +43,17 @@ private static void RegisterHandlers(
var assemblies = assemblyMarkerTypes.Select(t => t.Assembly).ToArray();
var lifetime = options.HandlerLifetime;
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(ICommandHandler<,>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithLifetime(lifetime));
-
+ ScanAndRegister(services, assemblies, typeof(ICommandHandler<,>), options.OnlyPublicClasses, lifetime);
// feature #141 - Register void command handlers
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(ICommandHandler<>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithLifetime(lifetime));
-
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(IQueryHandler<,>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithLifetime(lifetime));
-
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(INotificationHandler<>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithLifetime(lifetime));
+ ScanAndRegister(services, assemblies, typeof(ICommandHandler<>), options.OnlyPublicClasses, lifetime);
+
+ ScanAndRegister(services, assemblies, typeof(IQueryHandler<,>), options.OnlyPublicClasses, lifetime);
+
+ ScanAndRegister(services, assemblies, typeof(INotificationHandler<>), options.OnlyPublicClasses, lifetime);
// Register streaming query handlers
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(IStreamQueryHandler<,>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithLifetime(lifetime));
+ ScanAndRegister(services, assemblies, typeof(IStreamQueryHandler<,>), options.OnlyPublicClasses, lifetime);
}
private static void RegisterProcessors(
@@ -90,28 +64,51 @@ private static void RegisterProcessors(
var assemblies = assemblyMarkerTypes.Select(t => t.Assembly).ToArray();
// Register pre-processors
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(IRequestPreProcessor<>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithTransientLifetime());
+ ScanAndRegister(services, assemblies, typeof(IRequestPreProcessor<>), options.OnlyPublicClasses, ServiceLifetime.Transient);
// Register post-processors with response
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(IRequestPostProcessor<,>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithTransientLifetime());
+ ScanAndRegister(services, assemblies, typeof(IRequestPostProcessor<,>), options.OnlyPublicClasses, ServiceLifetime.Transient);
// Register post-processors without response (for void commands)
- services.Scan(scan => scan
- .FromAssemblies(assemblies)
- .AddClasses(classes => classes
- .AssignableTo(typeof(IRequestPostProcessor<>)), options.OnlyPublicClasses)
- .AsImplementedInterfaces()
- .WithTransientLifetime());
+ ScanAndRegister(services, assemblies, typeof(IRequestPostProcessor<>), options.OnlyPublicClasses, ServiceLifetime.Transient);
+ }
+
+ private static void ScanAndRegister(
+ IServiceCollection services,
+ IEnumerable assemblies,
+ Type openGenericInterface,
+ bool onlyPublicClasses,
+ ServiceLifetime lifetime)
+ {
+ foreach (var assembly in assemblies)
+ {
+ Type[] types;
+ try
+ {
+ types = onlyPublicClasses
+ ? assembly.GetExportedTypes()
+ : assembly.GetTypes();
+ }
+ catch (ReflectionTypeLoadException ex)
+ {
+ types = ex.Types.Where(t => t != null).ToArray();
+ }
+
+ foreach (var type in types)
+ {
+ if (type.IsInterface || type.IsAbstract || type.IsGenericTypeDefinition)
+ continue;
+
+ var matchingInterfaces = type.GetInterfaces()
+ .Where(i => i.IsGenericType &&
+ i.GetGenericTypeDefinition() == openGenericInterface);
+
+ foreach (var serviceType in matchingInterfaces)
+ {
+ services.Add(new ServiceDescriptor(serviceType, type, lifetime));
+ }
+ }
+ }
}
private static void RegisterPipelineBehaviors(IServiceCollection services, MediatorOptions options)
diff --git a/src/Cortex.Tests/Mediator/Tests/HandlerLifetimeTests.cs b/src/Cortex.Tests/Mediator/Tests/HandlerLifetimeTests.cs
index 947f8c2..47eae2d 100644
--- a/src/Cortex.Tests/Mediator/Tests/HandlerLifetimeTests.cs
+++ b/src/Cortex.Tests/Mediator/Tests/HandlerLifetimeTests.cs
@@ -10,7 +10,7 @@ namespace Cortex.Tests.Mediator.Tests
{
#region Test Types for Handler Lifetime Tests
- // These types live in this assembly so Scrutor can discover them via the marker type.
+ // These types live in this assembly so assembly scanning can discover them via the marker type.
public class LifetimeTestCommand : ICommand
{