0

I have a project A with an IWorker dependency which has many dependencies (context, repositories, etc.). How can I implement IWorker in project B without registering all dependencies? Or what is the correct way to call IWorker in project B?

Example:

Dependency:

public interface IDependency 
{
    public void SomeMethod();
}

public class SimpleDependemcy : IDependency
{
    public void SomeMethod()
    {
        //Logic
        throw new NotImplementedException();
    }
}

Worker:

public interface IWorker 
{
    public void DoWork();
}

public class Worker : IWorker
{
    private readonly IDependency _dependency;

    public Worker(IDependency dependency)
    {
        _dependency = dependency;
    }

    public void DoWork()
    {
        //Do something
        throw new NotImplementedException();
    }
}

Registration in project A:

services.AddScoped<IDependency, SimpleDependemcy>();
services.AddScoped<IWorker, Worker>();

I want to use worker in project B like:

public class SomeService 
{
    private readonly IWorker _worker;

    public SomeService(IWorker worker) 
    {
        _worker = worker;
    }
}

without any registration or simple services.AddScoped<IWorker, Worker>(); in project B. Is it possible? If not, what is correct way to use IWorker implementation in project B?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Pedro
  • 63
  • 1
  • 7
  • What have you tried? Kindly share your implementation. – FortyTwo Feb 16 '23 at 08:07
  • I thihk yes. I need just register all dependecies in one project and then reuse it in another without full registration – Pedro Feb 16 '23 at 08:08
  • 1
    pretty hard to follow without some sample-code. Can you share your interface please? And what do you mean by "call `IWorker` in project B"? – MakePeaceGreatAgain Feb 16 '23 at 08:14
  • You can encapsulate the registration into an extension method on `IServiceCollection` (I thinnk it was). Then you can have in Project A something like `AddProjectA()` and use that in Project B's DI setup and voilá. – Fildor Feb 16 '23 at 08:42

2 Answers2

1

Dependency injection work on classes, it does not really care about what project things is in.

The simplest organization is to just make all your registrations in the application project, whatever project that happens to be. But this may cause lots of duplicate code if you have lots of classes and multiple applications using some project.

So you could just delegate registrations to a method in each project:

// In Project A
public static void DoRegistrations(ServiceCollection services){
    services.AddScoped<IDependency, SimpleDependemcy>();
    services.AddScoped<IWorker, Worker>();
}
...
// In ProjectB
public static ServiceProvider CreateServiceProvider(){
    var serviceCollection = new ServiceCollection();
    ProjectA.Namespace.DoRegistrations(serviceCollection);
    serviceCollection.AddTransient<SomeService>();
    var container = serviceCollection.BuildServiceProvider();
    return container;
}

An more advanced solution is to put the registration method in a class implementing some interface, for example:

public interface IModule{
    public void DoRegistrations(ServiceCollection services);
}

This makes it possible to use reflection to find all implementations in all loaded projects, and do all the registrations. A downside with this pattern is that it can be a big WTF-moment for anyone not familiar with the pattern, so use with care.

Whatever solution you end up with, consider writing some automated tests to check that all registrations have been done. It is my experience that missing registrations is a common source of runtime failures, so detecting problems early is useful.

JonasH
  • 28,608
  • 2
  • 10
  • 23
0

It seems like a common dependency setup. In order to demonstrate I will change IWorker to IMyRepository, and SomeService to MyAppService. So, in this setup, you would (generally speaking) create an abstraction project which defines how a certain dependency should be used and what a certain implementation should adhere to.

I would start by creating the MyProject.Repository.Abstraction project that will contain the repository interface(s).

Then I would implement this interface in a platform specific manner (say MSSQL with MSSQL dependencies) in MyProject.Repositry.Mssql project as MyRepostory:IMyRepository

Similarly, I could create MyProject.Services.Abstractions but it is not relevant. I could now use MyProject.Service project with a reference to MyProject.Repository.Abstractions (not the platform specific implementation project) to implement MyAppService which utilizese the IMyRepository interface.

Finally, the highest level client project, MyProject.Client would reference both the implementation and the abstraction projects to be able to do the dependency injection. This way you can use the abstractions in other projects as reference.

On another note on using this approach, projects with highest abstraction would have higher afferent coupling getting your projects closer to I curve (see also What is Abstractness vs. Instability Graph?).

Can Bilgin
  • 471
  • 2
  • 6