Skip to content

Instantly share code, notes, and snippets.

@dannyc02
Created February 18, 2016 18:09
Show Gist options
  • Save dannyc02/f8d2cb03115262e85b8d to your computer and use it in GitHub Desktop.
Save dannyc02/f8d2cb03115262e85b8d to your computer and use it in GitHub Desktop.
CQRS with generic types
using FluentAssertions;
using MediatR;
using NUnit.Framework;
using StructureMap;
using StructureMap.Graph;
using StructureMap.Graph.Scanning;
using System;
using System.Collections.Generic;
using System.Linq;
using Container = StructureMap.Container;
namespace MediatorTests
{
[TestFixture]
public class UnitTest1
{
public class HomeItem : IItem
{
}
[Test]
public void ShouldResolveGenericHandler()
{
var container = new Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.IncludeNamespaceContainingType<HomeItem>();
scanner.AddAllTypesOf(typeof(IRequestHandler<,>));
scanner.With(new AddRequestHandlersWithGenericParametersToRegistry());
scanner.WithDefaultConventions();
});
cfg.For<SingleInstanceFactory>().Use<SingleInstanceFactory>(ctx => t => ctx.GetInstance(t));
cfg.For<MultiInstanceFactory>().Use<MultiInstanceFactory>(ctx => t => ctx.GetAllInstances(t));
cfg.For<IMediator>().Use<Mediator>();
});
var mediator = container.GetInstance<IMediator>();
Console.Write(container.WhatDoIHave());
var response = mediator.Send(new CreateItemCommand<HomeItem>());
var response2 = mediator.Send(new CreateHomeItemCommand());
response.Should().NotBeNull();
response2.Should().NotBeNull();
}
}
public class CreateHomeItemCommand : IRequest<UnitTest1.HomeItem>
{
}
public class CreateHomeItemCommandHandler : IRequestHandler<CreateHomeItemCommand, UnitTest1.HomeItem>
{
public UnitTest1.HomeItem Handle(CreateHomeItemCommand message)
{
return new UnitTest1.HomeItem();
}
}
public class CreateItemCommand<T> : IRequest<T> where T : IItem
{
}
public class CreateItemCommandHandler<T> : IRequestHandler<CreateItemCommand<T>, T> where T : IItem
{
public T Handle(CreateItemCommand<T> message)
{
return Activator.CreateInstance<T>();
}
}
public class AddRequestHandlersWithGenericParametersToRegistry : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
var commandMappings = GetRequestHandlersWithGenericParameters(types);
foreach (var commandMapping in commandMappings)
{
foreach (var concreteClass in types.FindTypes(TypeClassification.Concretes))
{
if (concreteClass.GetInterfaces().Contains(typeof(IItem)))
{
var genericCommand = commandMapping.Command.MakeGenericType(concreteClass);
var interfaceHandlerType = typeof(IRequestHandler<,>).MakeGenericType(genericCommand, concreteClass);
var concreteHandlerType = commandMapping.Handler.MakeGenericType(concreteClass);
registry.For(interfaceHandlerType).Use(concreteHandlerType);
}
}
}
}
private IEnumerable<CommandMapping> GetRequestHandlersWithGenericParameters(TypeSet types)
{
foreach (var concreteType in types.FindTypes(TypeClassification.Concretes))
{
var genericInterfaces = concreteType.GetInterfaces().Where(x => x.IsGenericType);
foreach (var genericInterface in genericInterfaces)
{
if (genericInterface.GetGenericTypeDefinition() == typeof (IRequestHandler<,>))
{
var requestHandlerType = concreteType;
var commandParameterType = genericInterface.GetGenericArguments()[0];
if (commandParameterType.IsGenericType)
{
yield return new CommandMapping { Command = commandParameterType.GetGenericTypeDefinition(), Handler = requestHandlerType };
}
}
}
}
}
}
public class CommandMapping
{
public Type Handler { get; set; }
public Type Command { get; set; }
}
public interface IItem
{
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment