tmm360
tmm360

Reputation: 414

Handle IoC configuration with shared dependencies between projects

I've a root project (root), some modules (A, B), and these modules have some external dependencies (Z). I'm using an IoC container.

I'm using C# here, but is a generic pattern question. Let say that my container is services, and I can initialize IoC configuration with use of extension methods. So in root project I'm writing:

services.AddModuleA();
services.AddModuleB();

On module A I've this method:

public static void AddModuleA(this IServiceCollection services)
{
    // Init module internal services.
    //services.AddScoped<IA1Service, A1Service>();
    //...

    // Init module external dependencies.
    services.AddDependencyZ();
}

On module B I've a similar method:

public static void AddModuleB(this IServiceCollection services)
{
    // Init module internal services.
    //...

    // Init module external dependencies.
    services.AddDependencyZ();
}

Obviously Z dependency was already been added, so this tells me that I should not configure it inside a module extension method, and I should rather declare its configuration in root project:

services.AddModuleA();
services.AddModuleB();
services.AddDependencyZ();

But doesn't this break the Least Knowledge principle? Importing and configuring a module A (or B) will bring to a cascade explicit declaration of all dependency configurations.

And related question, is declaring the extension methods AddModuleA() and AddModuleB() a bad pattern at all? Could be a better idea to configure directly on root only services that I will use? And in this case (a bit extreme), what about config of internal use only class?

Upvotes: 2

Views: 209

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233317

Supposing that those extension methods are defined in your application's Composition Root, why don't you just remove the call to AddDependencyZ from within AddModuleA and AddModuleB?

public static void AddModuleA(this IServiceCollection services)
{
    // Init module internal services.
    //services.AddScoped<IA1Service, A1Service>();
    //...
}

public static void AddModuleB(this IServiceCollection services)
{
    // Init module internal services.
    //...
}

You would then, as you write, configure the container in the Composition Root (this is the Register phase in the RRR pattern):

services.AddModuleA();
services.AddModuleB();
services.AddDependencyZ();

Does this break the Least Knowledge principle? Yes, it does, but that's one of the many drawbacks of using a DI Container.

I recommend Pure DI instead of using a DI Container. That would make the problem disappear because all the code in the OP would be redundant.

Upvotes: 2

Related Questions