This project is read-only.

GetAllInstances not working while only registered instance

Sep 27, 2014 at 2:34 PM
Edited Sep 27, 2014 at 2:36 PM
I register my component like this:
container.RegisterManyForOpenGeneric(typeof(INotificationHandler<>), typeof(IMediator).Assembly, typeof(Ping).Assembly); 
when I call GetAllInstances<INotificationHandler<TNotification>>() SimpleInjector don't return any instance but I call GetAllInstance<INotificationHandler<TNotification>>() return single registered object.

How can I get all instance using GetAllInstances method while only registered instance ?
Sep 27, 2014 at 2:36 PM
below registration type resolved my issue, but registration not include Contravariant type of INotificationHandler
  container.RegisterManyForOpenGeneric(typeof(INotificationHandler<>), 
                AccessibilityOption.PublicTypesOnly,
                 (serviceType, implTypes) => container.RegisterAll(serviceType, implTypes),
                 typeof(IMediator).Assembly, typeof(Ping).Assembly);
Sep 27, 2014 at 2:37 PM
I solved Contravariant problem using ResolveUnregisteredType (dot_NET_Junkie |implementaion)
public static class SimpleInjectorExtensions
    {
        public static void AllowToResolveVariantTypes(this Container container)
        {
            container.ResolveUnregisteredType += (sender, e) =>
            {
                Type serviceType = e.UnregisteredServiceType;

                if (!serviceType.IsGenericType)
                {
                    return;
                }

                Type def = serviceType.GetGenericTypeDefinition();

                var registrations = (
                    from r in container.GetCurrentRegistrations()
                    where r.ServiceType.IsGenericType
                    where r.ServiceType.GetGenericTypeDefinition() == def
                    where serviceType.IsAssignableFrom(r.ServiceType)
                    select r)
                    .ToArray();

                if (!registrations.Any())
                {
                    // No registration found. We're done.
                }
                else if (registrations.Length == 1)
                {
                    var registration = registrations[0];
                    e.Register(registration.BuildExpression());
                }
                else
                {
                    var names = string.Join(", ", registrations
                        .Select(r => string.Format("{0}", r.ServiceType)));

                    throw new Exception(string.Format(
                        "It is impossible to resolve type {0}, because there are {1} " +
                        "registrations that are applicable. Ambiguous registrations: {2}.",
                        serviceType, registrations.Length, names));
                }
            };
        }
    }
Sep 27, 2014 at 2:53 PM
Simple Injector explicitly differentiates between registrations of collections and normal registrations. This behavior is described in the The API clearly differentiates the registration of collections section of the Simple Injector Design Principles.

What this means is that the container doesn't allow you to make multiple registrations for the same type and resolve them as a collection. You either register a single item, or you register a collection. The Design Principles wiki explains why this behavior is chosen.

This behavior is used by other parts of the library as well, such as the RegisterManyForOpenGeneric method. This method will simply search for all non-generic implementations of the given interface and calls container.Register on each of them. But in case you have multiple implementations of the same closed-generic abstraction, Simple Injector throws an exception the second time container.Register is called for that particular abstraction.

And you already found the solution to this, which is to pass in a callback delegate into the RegisterManyForOpenGeneric to override the way those registrations are made. With the callback delegate, the RegisterManyForOpenGeneric leaves the registration part up to you and you can call container.RegisterAll.

But this won't work with covariance and contra-variance. As a matter of fact, Simple Injector has no out of the box support for variance. The reason for this is that it is not possible for Simple Injector determine in what way variant types should be resolved; it depends completely on the design of your application, so you'll have to describe this explicitly. This blog post goes into more detail how you can resolve variant types with Simple Injector.
Marked as answer by dot_NET_Junkie on 9/28/2014 at 3:36 AM