While testing NServiceBus and MassTransit – yes I
need a service bus framework for my current project – I’ve seen that both
library where relying on an IOC container, in two different ways.
Warning: This article is not to flame these two frameworks that seems of
great quality. There are still few guidance on using IOC containers in
libraries. This is the topic of this post.
The NServiceBus way
NServiceBus relies on Spring or Castle
You can notice it when instantiating the Bus :
var bus = NServiceBus.Configure.With()
.SpringBuilder() // or .CastleWindsorBuilder()
And when looking at the library with Reflector
Yes, the Spring framework and the Castle.Windsor are ILMerged in the NServiceBus assembly.
NServiceBus abstracts the container with the
NServiceBus.ObjectBuilder.IBuilder interface :
public interface IBuilder
object Build(Type typeToBuild);
IEnumerable<object> BuildAll(Type typeToBuild);
void BuildAndDispatch(Type typeToBuild, Action<object> action);
The MassTransit way
MassTransit adopts a slightly different strategy.
The base is still the same.
It uses the CommonServiceLocator to have a ‘standard’ interface to hide the
actual IOC container implementation.
It provides implementations for the most common IOC frameworks (Castle.Windsor, NInject, StructureMap and Unity – but it doesn’t work so well…) through additional
The big difference is in the library configuration. You configure the
container (through code or configuration). Then encapsulate the container in a
Common Service Locator implementation that acts as an adapter. Finally give it
to the library.
What’s the problem
In both case, the intent is good, but hell is paved with good
In Mass Transit, the design is clearly made so that you can choose your
container and integrate the library seamlessly with it. You can manage the
configuration in your container the way you do it in your application.
But wait ! What if I don’t need an IOC container in my application
The other problem is that Mass Transit relies on some advanced IOC
capabilities like contextual configuration. The object instantiated for
IEndPoint should not be the same depending on the parent object. This scenario
is not handled by Unity for instance.
Maybe Unity is not good enough, but how can I know which other specific
feature Mass Transit relies on ? No clue.
And providing a library configuration through a container doesn’t seem a
best practice to me. The API gives no clues of what I should provide to the
library in order to run it.
The only way to know is to launch it, see where it throws an
unresolved dependency exception, add the dependency and retry !
And I’ll probably never know about optional dependencies.
On the other side, NServiceBus works with a NServiceBus specific
configuration (code and app.config) that indicates clearly what I must
provide to the library.
But Jak Charlton had a serious problem with NServiceBus. He’s
not using the same version of Castle.Windsor that the one merged in the NSB
assembly ! And the assembly load fails.
What’s the solution then ?
I clearly prefer the specific configuration scheme of NServiceBus, but how
can we solve the version problem ?
I will answer with another question :
Why does NServiceBus need two IOC container implementations
For library creators, I will propose this way to go :
- Choose the container that provides the features you need
- Use it in your infrastructure
- Create a clear configuration model that exposes the required and optional
dependencies that should be provided by the library user
- Consider creating a app.config specific configuration (there are good tools
in the framework for that)
- ILMerge your container framework as internal in your
The alternative to ILMerge is to fork your framework (if it’s open source)
and put it as internal directly in your code.
- No conflict with potential other versions of the container framework
- A clear discoverable configuration
- No need to use a IOC container to use the library.
What if the container needs to inject dependencies in the user objects
Both NServiceBus and MassTransit instantiate user’s objects on the fly.
How can the user add it’s own dependencies if he has no access to the
Let’s step back a little and consider what we would do if there was no
- We would use Activator.CreateInstance to create the object.
- Then we would consider it would not let the library user enough options, so
we would propose a hook so that the user can manage the instantiation himself.
It could be a callback or an interface.
When instantiating user objects with the internal framework IOC
container, you remove to your users the right to manage the instantiation
So come back to this good practice. If the user wants to use a IOC container
to instantiate his objects with dependencies, let him do this his own way. And
his container will not be loaded with all the framework internal dependencies,
this will avoid other conflicts.
Hide your IOC container framework inside your library, it’s a private
implementation detail of your framework and we don’t wanna know !
Choose the framework you like, hide it so that it cannot conflict with the
one I want to use and we will be friends !
It surely advocates for frameworks with a small footprint, but once again,
it’s a private detail.
Continued on IOC Container, Go Hide (part 2)