Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Cortex.Mediator/Cortex.Mediator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,5 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.3" />
<PackageReference Include="Scrutor" Version="6.0.1" />
</ItemGroup>
</Project>
101 changes: 49 additions & 52 deletions src/Cortex.Mediator/DependencyInjection/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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(
Expand All @@ -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<Assembly> 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)
Expand Down
2 changes: 1 addition & 1 deletion src/Cortex.Tests/Mediator/Tests/HandlerLifetimeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>
{
Expand Down