Search code examples
c#automapperunity-container

Dynamically registering multiple implementations of an interface with Unity (IValueResolver from AutoMapper


I have code that will dynamically scan assemblies for implementations of the AutoMapper Profile class and build a mapper for use with Unity DI. Recently, I have found the need to use the IValueResolver interface. This class would need to have a resource dependency injected in it in order to perform translations between models.

I can add one line to the automapper configuration that will force it to use unity to resolve the IValueResolvers.

    cfg.ConstructServicesUsing(type => container.Resolve(type));

I am having trouble figuring out how to register multiple instances of a generic Interface with Unity dynamically.

I could hard-code

    container.RegisterType<IValueResolver<Class1, Class2, string>,Class1ToClass2ValueResolver>();

But, I'd rather scan and register them all dynamically.


Solution

  • There may be a better way and this approach might be a bit naive and might not handle all nested type hierarchies or multiple implementations of the same generic interface but this approach does work for the posted case. Perhaps it could be cleaned up by using some of the Registration by Convention features.

    var resolverTypes = .AppDomain.CurrentDomain.GetAssemblies()
        .Where(a => !a.IsDynamic) // Exclude dynamic assemblies
        .Select(a => a.GetTypes())
        .SelectMany(t => t) // flatten Types for each assembly into one
        .Select(t => t.GetTypeInfo())
        .Where(t => 
            t.ImplementedInterfaces.Any(i =>
                i.IsGenericType && 
                i.GetGenericTypeDefinition().IsAssignableFrom(typeof(IValueResolver<,,>))))
        .Select(t => new
        {
            Inteface = t.ImplementedInterfaces.First(i =>
                i.IsGenericType && i.GetGenericTypeDefinition()
                                 .IsAssignableFrom(typeof(IValueResolver<,,>))),
            Type = t
        });
    
    var container = new UnityContainer();
    
    foreach (var resolverType in resolverTypes)
    {
        container.RegisterType(resolverType.Inteface, resolverType.Type);
        var resolver = container.Resolve(typeof(IValueResolver<Class1, Class2, string>));
        Debug.Assert(resolver.GetType() == typeof(Class1ToClass2ValueResolver));
    }
    

    The hard work is in getting the correct types: First get all assemblies, exclude dynamic assemblies, and flatten into an enumerable of types (instead of Enumerable<Type[]>). Next pick out only the classes that have a generic interface and match the open generic IValueResolver<,,> interface and return the type with the matching closed generic interface.

    Once we have that information it's just a matter of registering the mapping from the interface to the implementation. In this case for IValueResolver<ClassA, ClassB, string> to Class1ToClass2ValueResolver. The following are the example classes and interfaces used:

    public class Class1 { }
    
    public class Class2 { }
    
    public interface IValueResolver<U, V, W> { }
    
    public class Class1ToClass2ValueResolver : IValueResolver<Class1, Class2, string> { }