6

Consider I have an app that uses three libraries, lib1, lib2 and lib3. In each of the libraries I have implemented a Module that registers the dependencies that are implemented in that library.

Some of these implementations have their own dependencies, for instance, lib2 and lib3 might both need some implementations that exist in lib1.

My question is, do I let the module in lib2 and lib3 register the module in lib1 as part of their Load implementation? Is this going to register that module twice if my app registers the modules of lib2 and lib3?

Or do I refrain from letting a module register another module, leaving it up to the app with the drawback that some registrations might be missing at startup?

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
Dave Van den Eynde
  • 17,020
  • 7
  • 59
  • 90
  • This question is not about whether it's ok have libraries register their own registrations. They do not. They simply offer a facade to help in registering these dependencies, to be used by the composition root. – Dave Van den Eynde Nov 02 '16 at 11:21

4 Answers4

7

A little late I know but I thought it might be nice to answer the question rather than just quote scripture about how multiple composition roots are evil...

Is this going to register that module twice if my app registers the modules of lib2 and lib3?

Tested with Autofac 4.8.1 and it does:

public class Lib1Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib1Module");

        // Register Types...

    }
}

public class Lib2Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib2Module");

        builder.RegisterModule<Lib1Module>();

        // Register Types...

    }
}

public class Lib3Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib3Module");

        builder.RegisterModule<Lib1Module>();

        // Register Types...

    }
}

public class Program
{
    public void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<Lib2Module>();
        builder.RegisterModule<Lib3Module>();

        using(var container = builder.Build())
        {
            // Do Stuff
        }
    }
}

Outputs:

Registering Lib2Module
Registering Lib1Module
Registering Lib3Module
Registering Lib1Module

You can use the Properties dictionary on an IComponentRegistry/ContainerBuidler (The Module base class internally creates the Container builder it passes to Load with the properties from the IComponentRegistry - source) to work around this and force single registrations for modules, if the Load Method of Lib1Module is changed to:

protected override void Load(ContainerBuilder builder)
{
    if (builder.Properties.ContainsKey(GetType().AssemblyQualifiedName))
    {
        return;
    }
    builder.Properties.Add(GetType().AssemblyQualifiedName, null);

    Console.WriteLine("Registering Lib1Module");

    // Register Types...

}

Then the output becomes:

Registering Lib2Module
Registering Lib1Module
Registering Lib3Module

Obviously if Lib2Module/Lib3Module can then become dependencies of other modules similar code would have to be put into their Load method and similarly if any modules used AttachToRegistrationSource and/or AttachToComponentRegistration and wanted to make sure they were run only once they would also need the check. Alternatively (and probably preferably if this is something you need to do a lot) you could create your own class implementing IModule and do the check within Configure.

I have definitely made use of this pattern in production code to keep the amount of repetition down where I have multiple entry points with their own composition roots (e.g a web api, a web app and a recurring console app) that nonetheless share a large chunk of code and I can live with that making me a persona non grata among DI purists.

Ed Askew
  • 71
  • 1
  • 3
2

In general, there should be only one library that contains the configurations. This library is the start-up project and this place in the application where everything is wired up is commonly refered to as the Composition Root. Typically only startup projects have a composition root, and only when multiple start-up projects in a single solution share a lot of duplicate registration, you start to extract this code to a common location that those composition roots can reuse. But be careful: in general Composition Roots should not be reused.

Steven
  • 166,672
  • 24
  • 332
  • 435
2

I won't recommend doing registrations inside your libraries. In most case you should have one composition root that will compose all your application.

A Composition Root is a (preferably) unique location in an application where modules are composed together.

This concept is explained here composition root.

By the way, if your register a module multiple time, Autofac will register component multipe time. If you must have module inside your library you should only create module that register component of the library.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62
  • 1
    Well I have multiple composition roots, one for each app in my solution. Surely I don't need to rewrite all the registration code? If so, what's the point of having modules at all? – Dave Van den Eynde Oct 19 '16 at 09:27
  • Module can help you organize registration. It also allows you to attach to already registered component or registration source to modify the registration behavior. See http://docs.autofac.org/en/latest/configuration/modules.html for more information about *Autofac* Module – Cyril Durand Oct 19 '16 at 22:51
0

An Autofac Module is nothing more than a facade to aid in registering components. It should not call into other modules for the purpose of registering implementations known to be dependencies of its own registrations, because that would tie the two modules together, increasing coupling.

Moreover, if the same module is registered multiple times, the registrations themselves are applied multiple times as Autofac does not keep track of modules that have already been registered. This usually does not pose a problem unless the composition root inadvertently nullifies any registrations meant to override existing ones.

Dave Van den Eynde
  • 17,020
  • 7
  • 59
  • 90
  • 1
    Sorry I know this one is old but I don't get why would you not declare the dependencies of your Module if you have them. Why should the user of the module be required to know what you need to use? – Filip Cordas Jul 04 '18 at 12:35
  • Well the most practical reason is that it may cause dependencies to be registered twice. – Dave Van den Eynde Jul 07 '18 at 12:38