Skip to content

Instantly share code, notes, and snippets.

@seesharper
Created September 18, 2019 13:37
Show Gist options
  • Save seesharper/1ddb64595f4534807626ac7586b4443f to your computer and use it in GitHub Desktop.
Save seesharper/1ddb64595f4534807626ac7586b4443f to your computer and use it in GitHub Desktop.
QueryHandle and CommandHandler registration
/// <summary>
/// Extends the <see cref="IServiceRegistry"/> interface
/// </summary>
public static class ContainerExtensions
{
/// <summary>
/// Registers all implementations of the <see cref="ICommandHandler{TCommand}"/> interface.
/// </summary>
/// <param name="serviceRegistry">The target <see cref="IServiceRegistry"/>.</param>
/// <returns></returns>
public static IServiceRegistry RegisterCommandHandlers(this IServiceRegistry serviceRegistry)
{
var commandTypes =
Assembly.GetCallingAssembly()
.GetTypes()
.Select(t => GetGenericInterface(t, typeof(ICommandHandler<>)))
.Where(m => m != null);
RegisterHandlers(serviceRegistry, commandTypes);
serviceRegistry.Register<ICommandExecutor>(factory => new CommandExecutor(factory), new PerScopeLifetime());
serviceRegistry.Register<IBus, Bus>(new PerScopeLifetime());
return serviceRegistry;
}
/// <summary>
/// Registers all implementations of the <see cref="IQueryHandler{TQuery,TResult}"/> interface.
/// </summary>
/// <param name="serviceRegistry">The target <see cref="IServiceRegistry"/>.</param>
/// <returns></returns>
public static IServiceRegistry RegisterQueryHandlers(this IServiceRegistry serviceRegistry)
{
var commandTypes =
Assembly.GetCallingAssembly()
.GetTypes()
.Select(t => GetGenericInterface(t, typeof(IQueryHandler<,>)))
.Where(m => m != null);
RegisterHandlers(serviceRegistry, commandTypes);
serviceRegistry.Register<IQueryExecutor>(factory => new QueryExecutor(GetCurrentScope(factory)), new PerScopeLifetime());
serviceRegistry.Register<IBus, Bus>(new PerContainerLifetime());
return serviceRegistry;
}
private static IServiceFactory GetCurrentScope(IServiceFactory serviceFactory)
{
// NOTE: Maybe we should look into LightInject and make sure that we pass the current scope rather than the container instance.
return ((IServiceContainer)serviceFactory).ScopeManagerProvider.GetScopeManager(serviceFactory).CurrentScope;
}
private static (Type, Type)? GetGenericInterface(Type type, Type genericTypeDefinition)
{
var closedGenericInterface =
type.GetInterfaces()
.SingleOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == genericTypeDefinition);
if (closedGenericInterface != null)
{
var constructor = type.GetConstructors().FirstOrDefault();
if (constructor != null)
{
var isDecorator = constructor.GetParameters().Select(p => p.ParameterType)
.Contains(closedGenericInterface);
if (!isDecorator)
{
return (closedGenericInterface, type);
}
}
}
return null;
}
private static void RegisterHandlers(IServiceRegistry registry, IEnumerable<(Type serviceType, Type implementingType)?> handlers)
{
foreach (var handler in handlers)
{
if (handler.HasValue)
{
registry.Register(handler.Value.serviceType, handler.Value.implementingType, handler.Value.implementingType.FullName);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment