Configuration with ReactiveUI, moving from Ninject to SI

May 24, 2013 at 9:05 PM
I need to translate this code using Ninject to SI
  public AppBootstrapper(string userInit)
        {
            IKernel kernel = CreateStandardKernel(userInit);

            // Set up NInject to do DI
            RxApp.ConfigureServiceLocator(
                getService: (iface, contract) =>
                {
                    if (contract != null) return kernel.Get(iface, contract);
                    return kernel.Get(iface);
                },
                getAllServices: (iface, contract) =>
                {
                    if (contract != null) return kernel.GetAll(iface, contract);
                    return kernel.GetAll(iface);
                },
                register: (realClass, iface, contract) =>
                {
                    IBindingWhenInNamedWithOrOnSyntax<object> binding = kernel.Bind(iface).To(realClass);
                    if (contract != null) binding.Named(contract);
                });

            RxApp.GetFieldNameForPropertyNameFunc = x =>
            {
                char[] arr = x.ToCharArray();
                arr[0] = char.ToLower(arr[0]);
                return '_' + new String(arr);
            };
        }
Anyone using RxUI with SI, this is the final step and then Ninject is retired (-:
Coordinator
May 24, 2013 at 10:00 PM
Edited May 24, 2013 at 10:00 PM
For Simple Injector this might look like this:
public AppBootstrapper(string userInit)
{
    Container container = CreateContainer(userInit);

    RxApp.ConfigureServiceLocator(
        getService: (serviceType, key) =>
        {
            if (key != null) throw new NotSupportedException();
            return container.GetInstance(serviceType);
        },
        getAllServices: (serviceType, key) =>
        {
            if (key != null) throw new NotSupportedException();
            return container.GetAllInstances(serviceType);
        },
        register: (implementationType, serviceType, key) =>
        {
            if (key != null) throw new NotSupportedException();

            container.Register(serviceType, implementationType, Lifestyle.Transient);
        });
}
Please note the following:
  • Simple Injector does not support keyed registrations out of the box (which is what I think that string value is for). For more information, read this and for a possible work around take a look at this. How to handle this depends a bit on what ReactiveUI expects.
  • Simple Injector does not support making new registrations after a call to GetInstance or GetAllInstances is made. Depending on how ReactiveUI calls that register delegate, you could get into trouble. Read more here.
If you have any trouble with this, don't hesitate to contact me directly. I'm sure we can solve these problems.
May 24, 2013 at 10:23 PM
Edited May 24, 2013 at 10:24 PM
We are getting closer

I am getting this error now:
Couldn't find a ICreatesObservableForProperty for Propertydesigner.ViewModels.DocumentViewModel. This should never happen, your service locator is probably broken.

RxUI is calling container.Register(serviceType, implementationType, Lifestyle.Transient); to set up it' one types and that's where the error is coming from.
I have tried to change Lifestyle.Transient to Lifestyle.Singleton but that don't changes anything.

and also added this:
   var con = new Container();
   con.Options.AllowOverridingRegistrations = true;
May 24, 2013 at 10:51 PM
The problem is as you already have described in bullet #2
Simple Injector does not support making new registrations after a call to GetInstance or GetAllInstances is made. Depending on how ReactiveUI calls that register delegate, you could get into trouble. Read more here.
But I think that what RxUI is doing is OK, first get the concrete type for a view and then inject it's own extensions. Will you recommend me to stick with Ninject? I hope not because I really like this:
container.RegisterManyForOpenGeneric(typeof(IValidate<>), 
    typeof(IValidate<>).Assembly);
And this
container.RegisterDecorator(
    typeof(ICommandHandler<>),
    typeof(ValidationCommandHandlerDecorator<>));
Coordinator
Jul 3, 2013 at 10:14 AM
Simple Injector 2.3 has just been released and it will make your integration scenario easier. It now contains a AppendToCollection extension method in the SimpleInjector.Advanced namespace. This extension method allows you to add registrations to a collection of registrations on a one-by-one basis. For instance:
var container = new Container();

var tran = Lifestyle.Transient;
var type = typeof(ILogger);

container.AppendToCollection(type, tran.CreateRegistration(type, typeof(DbLogger), container));
container.AppendToCollection(type, tran.CreateRegistration(type, typeof(FileLogger), container));
container.AppendToCollection(type, tran.CreateRegistration(type, typeof(ConsoleLogger), container));

// Resolve
var loggers = container.GetAllInstances<ILogger>();
I hope this helps.
Marked as answer by dot_NET_Junkie on 3/2/2014 at 10:49 AM