During my recent adventures implementing NServiceBus and configuring it to play nicely with StructureMap I ran across a confusing exception.
If you’re under deadline, feel free to skip to the end.
The exception that started it all
StructureMap.Exceptions.StructureMapConfigurationException: StructureMap configuration failures:
Source: Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=184.108.40.206, Culture=neutral, PublicKeyToken=e60ad81abae3c223
Type Instance 'b9b47db6-ca34-433c-878d-7c05092dc29b' (Configured Instance of NServiceBus.Installation.INeedToInstallSomething, NServiceBus.Core, Version=220.127.116.11, Culture=neutral, PublicKeyToken=9fc386479f8a226c) cannot be plugged into type NServiceBus.Installation.INeedToInstallSomething, NServiceBus.Core, Version=18.104.22.168, Culture=neutral, PublicKeyToken=9fc386479f8a226c
At first this had me baffled. After much googling, binging, and waiving my arms up and down while turning in circles, I was downright frustrated.
“What do you mean I can’t plug a type implementing INeedToInstallSomething into a dependency that needs an INeedToInstallSomething?” I shouted at the heavens.
Eventually calmer heads prevailed and I realized that I had misread the exception message.
StructureMap was actually trying to tell me was that I (or someone acting on my behalf) had asked it to wire up the INeedToInstallSomething interface as if it were a concrete type that implemented itself.
If that seems a bit self-referential, do not panic.
While any given interface has the same signature as itself, StructureMap doesn’t know how to create instances of interfaces, only of the concrete types that are bound to them.
Stepping though the source code for NServiceBus to see how it’s magic pluggable IOC configuration works, I noticed that the exception was thrown by the following code:
If you look closely, you’ll notice that typeof(INeedToInstallSomething) is actually assignable from INeedToInstallSomething so in addition to all the concrete types that implement that interface, the code above also tried to register the interface itself as if it were a concrete type.
Here’s my solution:
If you have trouble seeing my change, head on over to github and check out the pull request
Have to hand it to the NServiceBus folks, my pull request as acknowledged, pulled, and integrated within 12 hours.
- If it looks like an interface, and acts like an interface, maybe it is an interface and can't be treated like a concrete type;
- When running on the edge of an open source project, always be ready to step through the source;
- If you find a problem, step up and submit a patch!