15

Autofac has modules, Windsor has Installers and StructureMap Registries ... with Simple Injector how can I pack configuration logic into reusable classes?

I have tried:

public interface IModule { }

public class FooModule : IModule
{
    public FooModule(SimpleInjector.Container container)
    {
        container.RegisterSingleton<IBar, Bar>();
        container.RegisterSingleton<IFoo, Foo>();
    }
}

And I use it in the Composition Root:

public static void Main(string[] args)
{
    var container = new SimpleInjector.Container();
    container.RegisterCollection<IModule>(new FooModule(container));
    ...
}

However, FooModule depends on container and maybe in not a good practice... see http://code.google.com/p/autofac/wiki/BestPractices:

If components have a dependency on the container, look at how they're using the container to retrieve services, and add those services to the component's (dependency injected) constructor arguments instead.

Steven
  • 166,672
  • 24
  • 332
  • 435
o3o
  • 1,094
  • 13
  • 23
  • Note that -even with Autofac- your `FooModule` will depend on the container (or with Autofac, the `ContainerBuilder, since Autofac splits the container in two types). Take a look at [this Autofac documentation](http://code.google.com/p/autofac/wiki/StructuringWithModules) and you'll clearly see that modules take this dependency. For a module, you simply need the container, but that doesn't matter since a module will be part of your composition root. – Steven May 26 '12 at 21:21

1 Answers1

18

A 'module' feature is deliberately left out of the Simple Injector core library, but there is a SimpleInjector.Packaging NuGet package that allows you to do this. 'Package' is the term Simple Injector uses. This library however, is nothing more than one IPackage interface and two extension methods. You can achieve the same by writing code like this:

A package:

public static class BootstrapperPackage
{
    public static void RegisterServices(Container container)
    {
        container.Register<IBar, Bar>(Lifestyle.Scoped);
        container.Register<IFoo, Foo>(Lifestyle.Singleton);            
    }
}

In your composition root:

public static void Main(string[] args)
{
    var container = new SimpleInjector.Container();

    BootstrapperPackage.RegisterServices(container);

    ...
}

The difference with the SimpleInjector.Packaging NuGet package is that this package defines an interface for you, and allows you to dynamically load multiple packages in one single line:

public class BusinessLayerPackage : IPackage
{
    public void RegisterServices(Container container)
    {
        container.Register<IBar, Bar>(Lifestyle.Scoped);
        container.Register<IFoo, Foo>(Lifestyle.Singleton);            
    }
}

public static void Main(string[] args)
{
    var container = new SimpleInjector.Container();

    container.RegisterPackages(AppDomain.CurrentDomain.GetAssemblies());
}

However, if you don't really need dynamic loading, using static methods (as shown above) is preferred, because it has the following advantages:

  • Makes loading modules very explicit and discoverable.
  • Makes it easy to select which modules to load and which not.
  • Makes it easy to pass along extra values to the RegisterServices methods, such as configuration values that such module requires. This prevents the module from taking a hard dependency on the configuration system.

For more information, please read this.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks Steven, ...but is it correct to pass container to other classes? – o3o Jan 24 '12 at 10:26
  • No it isn't, but a module is not part of the application code, but part of the [composition root](http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx), which makes it an infrastructure component. It is okay to use the container inside your infrastructure components. Mark Seemann describes this clearly [here](http://blog.ploeh.dk/2011/08/25/ServiceLocatorRolesVsMechanics.aspx). – Steven Jan 24 '12 at 10:55
  • 1
    Why was this feature left out of the core library? – Sam Jul 23 '14 at 05:29
  • @Sam: It's left out of the core library to keep the core library's API small. Packaging is a feature that's not needed very often and as I show in the code example, in most scenarios you can easily achieve the same without the SimpleInjector.Packaging NuGet package. – Steven Jul 23 '14 at 05:32
  • 1
    I find this feature really valuable when you have a solution with many projects and each project exposes both interfaces (for some services) and implementations (for other services). One (or even more) package(s) per-project, each up to define local registrations: clean. The possibility to load packages through assembly scanning provides very loose coupling between composition-root and other projects. – Marcello Apr 05 '16 at 06:47
  • @Marcello: Unless your application uses a plugin model, where assemblies are dropped in a 'plugin' directory and loaded dynamically, the application's entry point will _always_ have a [dependency on _all_ other assemblies](https://stackoverflow.com/questions/9501604/) in the system. It is the most _volatile_ part in the system and dynamically loading parts of your Composition Root dynamically doesn't change that. Package scanning is therefore discouraged for any assembly that is known at compile-time. – Steven Nov 21 '17 at 10:26
  • Thanks @Steven. My apps have not plugins. I am very interested in the best practice for a good composition root (mark seeman's book is only one of my readings) since, though I love DI, this aspect is still one of my 'hard steps'.I shared my current best practice here: https://github.com/supix/Diploy What I really like about this approach (see pros section) is to declare implementations as private classes. I would be very glad to learn a better practice. – Marcello Nov 27 '17 at 17:39
  • @Marcello: the [second edition](https://manning.com/seemann2) will contain [more detailed information](https://livebook.manning.com/#!/book/dependency-injection-in-dot-net-second-edition/chapter-4/v-6/99) about this. – Steven Nov 27 '17 at 18:00