This project is read-only.

RegisterManyForOpenGeneric not registering my generic service

Jul 10, 2013 at 12:53 PM
Hi,

We have just started using Simple Injector and are really liking it so far.
However I cannot seem to register the following generic service.
  1. interface:

public interface IMappingService<TSource, TDestination> 
        where TSource: SourceEntity
        where TDestination: DomainEntity
    {
        TDestination Map(TSource source,TDestination destination);
    }
  1. Implementation

public class MappingService<TSource, TDestination> : IMappingService<TSource, TDestination>
       where TSource:  SourceEntity
        where TDestination: DomainEntity
    {

        public TDestination Map(TSource source, TDestination destination)
        {
            return Mapper.Map(source, destination);
        }
    }
  1. Attempted Registration

container.RegisterManyForOpenGeneric(typeof(IMappingService<,>), typeof(IMappingService<,>).Assembly);
Despite the registration code definately running, this service does not appear in the container, and some the container.Verify() is then invalid.

Thanks for your help

sean
Coordinator
Jul 10, 2013 at 1:25 PM
Edited Jul 10, 2013 at 2:09 PM
You should use the RegisterOpenGeneric extension method instead to map an open generic abstraction to an implementation:
container.RegisterOpenGeneric(typeof(IMappingService<,>),
    typeof(MappingService<,>));
The RegisterManyForOpenGeneric extension method is Simple Injector's batch registration facility. The extension method will search the supplied assemblies for types that implement a closed generic version of the given abstraction. Any found type will get registered at that point and open generic types (such as your MappingService<TSource, TDestination>) will be skipped.

RegisterOpenGeneric on the other hand does no batch registration, but hooks onto the container's ResolveUnregisteredType event. This will result in the registration of a closed generic version of the given open generic registration at the time a closed generic version of the given abstraction is first requested. In other words, RegisterOpenGeneric itself does not register any types, but registers an event that allows a type to be register last-minute.

Their intend is quite different and allowing open generic types to be batch registered using ResolveUnregisteredType would not be appropriate in all cases. However, you will often see that those two methods are used together: The ResolveUnregisteredType is used to batch register a set of implementations and RegisterOpenGeneric is used to register a fallback type that is used in cases there is no appropriate implementation. Take a look at the following example for instance:
class CustomerMapper : IMappingService<CustomerDto, Customer> { }
class OrderMapper : IMappingService<OrderDto, Order> { }

// This call will register CustomerMapper and OrderMapper 
container.RegisterManyForOpenGeneric(typeof(IMappingService<,>),
    typeof(IMappingService<,>).Assembly);

// This call will ensure a closed version of MappingService<,> 
// is returned in case a IMappingService<,> is requested that 
// has no registration.
container.RegisterOpenGeneric(typeof(IMappingService<,>),
    typeof(MappingService<,>));

var o = container.GetInstance<IMappingService<OrderDto, Order>>();
var x = container.GetInstance<IMappingService<XDto, X>();

Assert.IsInstanceOfType(o, typeof(OrderMappingService));
Assert.IsInstanceOfType(x, typeof(MappingService<XDto, X>));
I hope this makes sense.
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:38 PM
Jul 10, 2013 at 3:03 PM
Hi Steven,

Thanks, that makes perfect sense.

Sean.