This project is read-only.

Moving from Unity to Simple Injector

May 21, 2013 at 2:38 PM
Unity allows me to pass construtor arguments when registering. Why the Simple Injector does not have this functionality?
private const int NumberOfInputs = 4;

container.Register<IInputConfigurationManager, InputConfigurationManager>(new InjectionConstructor(NumberOfInputs));

container.Register<IMixerOrchestrator, MixerOrchestrator>(
                Lifestyle.Singleton,
                new InjectionConstructor(NumberOfInputs, typeof(IVideoMixer), typeof(IEnumerable<IMixerInputHandler>), typeof(IEnumerable<IApplyFilterPreview>)));
How can I register the types above?
May 21, 2013 at 3:35 PM
Edited May 21, 2013 at 3:40 PM
A feature that allows auto-wiring constructors that contain both (service) dependencies and primitive values is deliberately left out of Simple Injector. In general, it's a bad idea to mix primitives and dependencies in a single constructor. This is bad because it often leads to configurations that are fragile and are hard to read and maintain.

Instead you should either:
  • Extract and group the primitives in their own 'configuration' type and inject that type into the service, or
  • Move those primitives to properties and use property injection.
For instance, instead of injecting an string connectionString value into multiple services, inject an IConnectionFactory into them. The connection factory implementation would of course depend on the connectionString, but this will be the only value in the constructor and it can be registered as follows:
container.RegisterSingle<IConnectionFactory>(
    new ConnectionFactory(connectionString));
Another option is to move primitive dependencies out of the constructor into a property. You can register an initializer to inject that property:
container.RegisterSingle<IConnectionFactory, ConnectionFactory>();

container.RegisterInitializer<ConnectionFactory>(instance =>
{
    instance.ConnectionString = connectionString;
});
Or when you have multiple components that need that connection string being injected, you can define an abstraction for them with a ConnectionString property which allows them all to be injected with one registration
public interface IMyApplicationConStrContainer
{
    string ConnectionString { get; set; }
}

public class SomeService : ISomeService, IMyApplicationConStrContainer
{
    public string ConnectionString { get; set; }
}

public class OtherService : IOtherService, IMyApplicationConStrContainer
{
    public string ConnectionString { get; set; }
}

// Will work on all classes that implement IMyApplicationConStrContainer
container.RegisterInitializer<IMyApplicationConStrContainer>(instance =>
{
    instance.ConnectionString = connectionString;
});
But again, when you have multiple classes that need the same connection string, it's usually better to hide that connection string behind an abstraction.

Mixing of primitives and dependencies is possible, but you will have to wire the type manually:
container.Register<IConnectionFactory>(() =>
    new ConnectionFactory(
        connectionString,
        container.GetInstance<IOtherDependency>()));
Or you can override the IConstructorInjectionBehavior as described in this blog post.
May 21, 2013 at 5:22 PM
Sometimes my services classes demand primitives times, like an integer in my example. Creating a factory just to get that single integer value, I think it's not worthy.
But I'm following the implementation of the blog post you mentioned.
May 21, 2013 at 10:11 PM
Edited May 21, 2013 at 10:11 PM
Sorry, but just one more thing:

From MSDN about Unity
"If you want to create more than one registration or mapping for the same type, you can create a named (non-default) mapping by specifying a name as a parameter, as shown in this code."
myContainer.RegisterType<IMyService, CustomerService>("Customers");
How can I achieve this in SimpleInjector. I don't really use this way, but the PRISM framework requires it for registering views:
public void RegisterView<T>()
        {
            container.RegisterType<object, T>(typeof(T).Name);
        }
where T is a View (Window or UserControl)
May 21, 2013 at 10:43 PM
Edited May 22, 2013 at 11:34 AM
I consider named registrations (as part of the framework) to be a bad thing and it can be prevented in most cases. With Unity you unfortunately need to use keyed registrations to work around limitations in its design (for applying decorators for instance).

I'm not sure you need keyed registrations in this case. Possibly you can simply register the type as follows:
container.Register<T>();
Which is a short cut for:
container.Register<T, T>();
Which is a short cut for:
container.Register<T, T>(Lifestyle.Transient);
May 22, 2013 at 1:15 PM
"The container can't be changed after the first call to GetInstance, GetAllInstances and Verify."

The code I've posted it's not called on bootstrap of the application. And it gives me that error.
May 22, 2013 at 1:45 PM
Edited May 22, 2013 at 1:51 PM
You will have to make sure that all registrations are done before the first call to GetInstance. This behavior is chosen explicitly to make the registration process easier and users less likely to shoot themselves in the foot when working with multi-threaded applications (most applications these days). And as a nice side effect, it allows Simple Injector to be extremely fast, since there are no locks taken in the application's happy path.

There are ways around this, by using unregistered type resolution for instance (and concrete types can be resolved automatically), but the general advice is to register all root types (and your views are probably resolved directly by Prism) explicitly, because this makes your configuration verifiable.

If you have trouble fixing this problem, please post the code here, or send me a message. I'll be happy to help you with this.
May 22, 2013 at 2:03 PM
Edited May 22, 2013 at 2:07 PM
I thought it would be easier to migrate to SimpleInjector and using the Bootstrapper library. However, the truth is that PRISM is so annoying about using a different container. That sucks. Look:
Image
The image is from http://msdn.microsoft.com/en-us/library/gg430861(v=pandp.40).aspx

I didn't like PRISM at all, but it was not my choice, I would go with Caliburn.Micro library, however I got the project already going on... So change it now, it's out of scope, sadly.

As for now, I give up migrating. It already took much time and this was not in the scope. But I find SimpleInjector nice, I'll certainly will use it in other projects.
May 22, 2013 at 3:07 PM
Although it's a pity you stop your effort, I do understand. It can take a lot of time to integrate a container with a framework when you're the first to try. Hopefully other enthusiasts will pick this up in the future. I will be happy to support anyone with my knowledge about Simple Injector to do so.

But if you're still trying, the following might help.

I assume that PRISM requests keyed instances through the IServiceLocator interface. The SimpleInjectorServiceLocatorAdapter class however throws an exception when one of the keyed methods of the IServiceLocator interface are called. What you can do however, is write a decorator that extends this behavior, as follows:
public class PrismSimpleInjectorServiceLocatorAdapter : IServiceLocator
{
    private readonly SimpleInjectorServiceLocatorAdapter adapter;
    private readonly Dictionary<string, int> nameIndexMappings;

    public PrismSimpleInjectorServiceLocatorAdapter(
        SimpleInjectorServiceLocatorAdapter adapter, 
        IEnumerable<Type> viewTypes)
    {
        this.adapter = adapter;

        // Make the mapping from type.Name -> index. (other mappings are possible)
        this.nameIndexMappings = viewTypes
            .Select((viewType, index) => new { viewType, index })
            .ToDictionary(item => item.viewType.Name, item => item.index);
    }

    public TService GetInstance<TService>(string key)
    {
        return (TService)this.GetInstance(typeof(TService), key);
    }

    public object GetInstance(Type serviceType, string key)
    {
        // Special handling for Views.
        if (serviceType == typeof(object))
        {
            int index = this.nameIndexMappings[key];

            // ElementAt is an O(1) operation in Simple Injector.
            return this.adapter.GetAllInstances<object>().ElementAt(index);
        }

        return this.adapter.GetInstance(serviceType, key);
    }

    public IEnumerable<TService> GetAllInstances<TService>()
    {
        return this.adapter.GetAllInstances<TService>();
    }

    public IEnumerable<object> GetAllInstances(Type serviceType)
    {
        return this.adapter.GetAllInstances(serviceType);
    }

    public TService GetInstance<TService>()
    {
        return this.adapter.GetInstance<TService>();
    }

    public object GetInstance(Type serviceType)
    {
        return this.adapter.GetInstance(serviceType);
    }

    public object GetService(Type serviceType)
    {
        return this.adapter.GetAllInstances(serviceType);
    }
}
With this decorator, you can do the following registration:
var container = new Container();

// Get or define a list of types for all Views
Type[] views = new[] { typeof(Shell) };

// Register those types as a collection of objects.
container.RegisterAll<object>(views);

// Create the special prism adapter and register that.
IServiceLocator adapter =
    new PrismSimpleInjectorServiceLocatorAdapter(
        new SimpleInjectorServiceLocatorAdapter(container), 
        views);

ServiceLocator.SetLocatorProvider(() => adapter);
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:33 PM