Stephen York Stephen York - 1 year ago 233
C# Question

Simple Injector and assembly scanning

I'm finally diving into the process of learning about IoC and other patterns and have run into an issue when trying to register open generics based on a list of assemblies. I'm building the core of my framework into separate class libraries and have a set of test projects where I declare some test classes inheriting from my framework.

Problem is that the framework.test.service dll where

AddPersonCommandHandler : ICommandHandler<AddPersonCommand>
isn't loaded at runtime so the
open generic fails to find anything. I need to create an
instance in advance then I get one extra assembly in my list and then it works.

Is there a simple way to force loading?

So this is the wireup code in my unit test project which holds the app domain and references to the other assemblies.

public Container SetupIoc()
var container = new Container();

container.Register(typeof(IUnitOfWork), typeof(EntityFrameworkUnitOfWork), Lifestyle.Singleton);

var assemblies = AppDomain.CurrentDomain.GetAssemblies();

container.Register(typeof(ICommandHandler<>), assemblies);


return container;

is in Database.Interface.dll
is in Core.dll
is in Test.Service.dll -- Part of a suite of projects settings up structure mimicking putting a real solution together and referenced by the Unit Tests.

So, what's happening is that the unit or work registration works fine I think because I'm specifying
directly whereas the
interface is in the Core which successfully binds. Post Verify() I only see the unit of work registration on
. To get the Test.Service.dll loading so the
show up I can instantiate an
in my TestInit method.

It just seems a little mad to have to manually load all the dlls for the project. And for the matter if I scan the executing folder for dlls, some are already loaded...will loading again play nicely or does it require careful checks to find out if it is already loaded?

Answer Source

You don't have to explicitly create an instance of AddPersonCommandHandler to make sure the assembly is loaded. All you have to do is reference a type in the assembly (such as your AddPersonCommandHandler) statically in code that runs before you call AppDomain.CurrentDomain.GetAssemblies(). For instance:

// Load BL assembly
Type type = typeof(AddPersonCommandHandler);

container.Register(typeof(ICommandHandler<>), AppDomain.CurrentDomain.GetAssemblies());

Best is to keep this reference in your Composition Root. This ensures that no matter from where the container is initialized (App_start or integration tests) the same assemblies are loaded.

A more explicit way is to make an explicit list of assemblies that should be used for registration:

// Adding the (redundant) namespace of the type makes it very clear to the
// user if this type is still located in the business layer.
Assembly[] businessLayerAssemblies = new[] {

container.Register(typeof(ICommandHandler<>), businessLayerAssemblies);
container.Register(typeof(IQueryHandler<,>), businessLayerAssemblies);
container.Register(typeof(IEventHandler<>), businessLayerAssemblies);
container.Register(typeof(IValidator<>), businessLayerAssemblies);

I prefer the latter approach, because this prevents scanning a bulk of assemblies that never contain useful types, while being very explicit about the assemblies (instead of implicitly referencing the type that happens to load its assembly).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download