Multiple registrations of the same type

Apr 28, 2013 at 7:29 PM
I think I've hit a wall on my attempt to impement NServiceBus' IContainer which is too bad because I've only got a couple failing tests remaining. :-D

There's a BuildAll method on the interface:
IEnumerable<object> BuildAll(Type typeToBuild)
I thought this was an easy match for GetAllInstances.

When the tests were failing, I started reading the docs and the rest of the web.

I take your point from here:
http://stackoverflow.com/a/15309961/214073

NServiceBus has several interfaces that can be implemented by consumers which is nice from an OCP point of view. Examples: IWantToRunWhenTheBusStarts, IMutateIncomingMessages.

I think that's great. From reading your comments, I think where the design misses the mark slightly is that calls to BuildAll/GetAllInstances should be paired with calls to RegisterAll or equivalent.

In their case, it probably works ok, because they will always call BuildAll for these things. It doesn't matter if zero, one, or many services were registered.

I can see from your perspective writing the injection framework itself, you don't want to allow Register/GetAllInstances combinations because, if there are multiple instances registered, what do you get back? It's happenstance.

You're pretty set on this and that makes sense to me.

So I've got three choices:
  • Convince the NSB guys to change the interface for IContainer to have a ConfigureAll or equivalent method and then implement that for all their existing containers
  • Hack something together where I "listen" to all the registrations and if I see one service registered multiple times, call RegisterAll, else Register and then test NSB to see that it actually adheres to those semantics. I'd probably need to add a "Done Registering" method to the interface to know when I can actually do the registrations. This seems like a bad bad road.
  • Abandon hope. :-D
Unless you have a magical idea of how I could make this work, I'm leaning towards #3.

Complete side note: in the course of figuring out what was going on, I read the docs about the decorators and interceptors. Very very nice. Thanks for this project.
Coordinator
Apr 29, 2013 at 7:50 AM
Again I have to congratulate you for all the research you are doing. I wish more developers acted like you are doing.

You are right about the Register/GetInstance and RegisterAll/GetAllInstances pairs.

Of course you should never abandon hope :-). But I don't give you much luck when requesting NSB to break the current interface. This is something they won't do easily, especially not an short notice.

On the other hand, changing this behavior in Simple Injector is not an option. First of all, I really believe in this design, because it makes the container easier to use (in most cases). Second, such change would be a big breaking change and would break existing applications, so that's a big no for me.

I can't imagine that there is no solid solution for this problem and if you're interested, I'm willing to cooperate with you to come up with a good solution. I think this would be a win-win. We will probably have a good solution within a few days which is probably what you need. We can open-source the solution so others can benefit from it as well. This is good for you, me, and the rest of the growing Simple Injector community. If you're interested, send me a private message, because I don't think this online forum is the most effective channel of communication to do this.
Coordinator
Jul 3, 2013 at 10:25 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(typeof(ILogger));
I hope this helps.
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:38 PM