It seems I might have gone a bit too far with decoupling.
I have a solution with asp.net projects and I use Ninject as IoC Container.
Most of the crucial parts that are used in the MVC projects are interfaces coming from a dedicated 'Contracts' library.
The actual implementation of the interfaces are located in other assemblies, that are not really referenced directly in the MVC app.
They are completely separate, MVC app only knows Contracts dll.
Ninject is loading all the referenced code in the composition root (at app startup)
kernel.Load("MyAssPrefix.*"); //load binding modules
kernel.Bind(x =>
{
x.FromAssembliesMatching("MyAssPrefix.*")
.SelectAllClasses()
.BindDefaultInterface();
}); //bind all the rest
Now, the problem is that since some of the assemblies are not referenced directly in the app, then dlls are not copied to the bin folder.
This causes problems at runtime - especially difficult, considering that the type has to be called to be resolved and throw error - which means you can compile, deploy and start getting errors weeks later, when some functionality is being used.
I have a 'CompositionRoot' project which is shared among few apps and which specifies some explicit bindings. Of course this project has all the required bits added as reference, but they are not called explicitly, so they are not included.
(When I simply drop required dlls to bin folder, it starts working ok)
I have a workaround for my problem which is to have a module that could bind assemblies, where I call a random class from that assembly which causes the dll to be added to output and it all to work OK.
public class BindAssembliesModule : NinjectModule
{
#region Overrides of NinjectModule
public override void Load()
{
this.Kernel.Bind(x => x.FromAssembliesMatching(typeof(MyAssPrefix.SomeClass).Assembly.GetName().Name).SelectAllClasses().BindDefaultInterface());
}
#endregion
}
This however seems hacky for a few reasons
- it is not obvious
- its redundant code that is not needed (except to ensure that references are not 'optiomized)
- its fragile - if the class that I picked is moved to a different assembly, this stops working
- it requires remembering about this hack when new assemblies are added
So, what is the proper way to handle that, what am I doing wrong?