This project is read-only.

Define all assemblies in one central location

Aug 6, 2014 at 10:18 PM
My Composition root is only ever concerned with one set of Assemblies throughout the registration process so personally I would benefit from being able to define all of the Assemblies in one central location at the start of the process of configuring the Container.

Is this something the container could/should support?
Aug 7, 2014 at 7:34 AM
Edited Aug 7, 2014 at 9:45 AM
I understand your request. With Simple Injector however, I try to balance between allowing advanced and experienced users to work with the framework, but on the other hand keeping Simple Injector simple and intuitive for new and unexperienced users.

Allowing to define all assemblies in one location, means that a new overload of RegisterManyForOpenGeneric must be added without the Assembly[] parameter. For instance:
container.RegisterManyForOpenGeneric(typeof(IValidator<>));
Since this is the overload with the least amount of parameters, new users will start using that, but at that point it's unclear what the framework will do in the background. It should of course pick up the global assembly configuration that you made when creating the container, but what should happen when the user didn't configure this.
  • Should this overload pick the assembly of the given type?
  • Should it select all assemblies that are already loaded in the app domain?
  • Should it throw an exception?
All options aren't really good in my opinion. Throwing an exception is not good, because a starting user will immediately be confronted with an exception, while the API could have let him in the right direction. Selecting all already loaded assemblies of the AppDomain (using AppDomain.CurrentDomain.GetAssemblies()) is not good as well, because you never know what assemblies are currently loaded and what not. It could lead to quite surprising outcome and small changes in the code base might change the outcome of this. Selecting only the assembly of the given open-generic type doesn't feel quite right, because this will definitely lead to "why isn't my type loaded" questions on the forum and stackoverflow.

So I rather have an API that steers the user into explicitly stating the assemblies he needs.

But as always, this behavior can be extended quite easily. For instance:
using SimpleInjector;
using SimpleInjector.Advanced;
using SimpleInjector.Extensions;

public static class SimpleInjectAssemblyExtensions
{
    private static readonly object key = new object();
        
    public static void WithDefaultAssemblies(this ContainerOptions options,
        params Assembly[] assemblies)
    {
        options.Container.SetItem(key, assemblies);
    }

    public static void RegisterManyForOpenGeneric(this Container container, 
        Type openGenericServiceType)
    {
        var assemblies = container.GetItem(key) as Assembly[];

        if (assemblies == null)
            throw new InvalidOperationException(
                "Call container.Options.WithDefaultAssemblies() first.");

        container.RegisterManyForOpenGeneric(openGenericServiceType, assemblies);
    }
}
With these extension methods you'll be able to do the following:
var container = new Container();
container.Options.WithDefaultAssemblies(AppDomain.CurrentDomain.GetAssemblies());

container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>));
container.RegisterManyForOpenGeneric(typeof(IQueryHandler<,>));
container.RegisterManyForOpenGeneric(typeof(IValidator<,>));
container.RegisterManyForOpenGeneric(typeof(IRepository<,>));
Marked as answer by dot_NET_Junkie on 8/11/2014 at 12:10 PM
Aug 7, 2014 at 9:40 AM
That's really cool. Thanks.