Dependency Injection outside of Controller

Viewed 89

Good day. I have a problem of understanding the Dependency Injection.

So what exactly do I need is to have access from child objects to parent objects. For example, I have my MainProgram object. This object creates another object, another object create 3-d objects and so on. Let's stop on child object #5

This child needs to have a reference to object #1.

I don't understand how to do this in a better way. But then I started to search and find something called Dependency Injection.

I really hope that this thing is the right answer for my issue (If not, please tell).

So here in my problem and example. I'm trying to create a WEB API for one of my services. Using ASP .NET Core 6

First, I created a simple class that will be MainProgram, when Server will receive POST request with needed data, it will launch some working in multi-threading.

public class MainProgram
{
   public int MaxThreads { get; set; }
   public int OrderCounter { get; set; }
   public AdjustableSemaphore Semaphore { get; set; }

   public MainProgram(int maxThreads)
   {
      MaxThreads = maxThreads;
      Semaphore = new AdjustableSemaphore(MaxThreads);
   }

   public async Task StartOperation(IApiOperation operation)
   {
      try
      {
         operation.Prepare();
         operation.Start();
         while (!operation.IsReady())
         {
            await Task.Delay(500);
         }
         operation.Finish();
      }
      catch (Exception e)
      {
         Console.ForegroundColor = ConsoleColor.Red;
         Console.WriteLine(e.Message);
         Console.ResetColor();
      }
   }

   public string OperationStatus(IApiOperation operation)
   {
      return operation.ShowDetails();
   }
}

Then I added this class to Program.cs for Dependency.

builder.Services.AddSingleton(program => new MainProgram(1000));

I made a Constructor for my Controller as it was in the example I read and all worked great.

Controller create instance of MainProgram by its own.

[ApiController]
[Route("/")]
public class ApiController : ControllerBase
{
  private MainProgram _mainProgram;
  public ApiController(MainProgram mainProgram)
  {
    _mainProgram = mainProgram;
  }
  
  [HttpPost]
  [Route("test")]
  public string Get()
  {
    TestOperation to = new TestOperation(_mainProgram);
    new Thread(() =>
    {
      var project =  _mainProgram.StartOperation(to);
    }).Start();
    return $"Started task #{to.Id}";
  }
}

The problems that I have are in this line

TestOperation to = new TestOperation(_mainProgram);

This TestOperation also has a Dependency from MainProgram. I understand that I can pass my private _mainProgram in it.

But let's pretend that TestOperation also has a child, and this child also has a child, and only the third one needs a link to MainProgram. I thought that's where Dependency Injection helps.

Main Question is

How can I create objects that have a constructor with dependency for MainProgram, If I cannot write new TestOperation(WITHOUT ATTRIBUTE)? It will be a syntax error.

1 Answers

I think you'd avoid the cycle of dependency;

If you couldn't avoid it ,you could try to inject the IServiceProvider into your services,and get the target service with provider.GetService() method,and you could try to create a Parameterservice or Static class to hold the parameter you need, I tried as below :

Services:

interface IA {int methodA();}
interface IB { int methodB(); }
interface IC { int methodC(); }
interface IParameterService {  }
public class ParameterService: IParameterService
{
    public  int APara;
    public  int BPara;
    public ParameterService(int para)
    {
        APara = para+1;
    }
}
    
public class A : IA
{
    private readonly IServiceProvider _provider;
    private readonly int Id;
    
    public A(IServiceProvider provider)
    {
        _provider = provider;
        Id = (provider.GetService(typeof(IParameterService)) as ParameterService).APara;
    }
    public int methodA()
    {
        return Id+1;
    }      

}
public class B : IB
{
    private readonly IServiceProvider _provider;
    
    public B(IServiceProvider provider)
    {
        _provider = provider;
    }
    public int methodB()
    {
        return (_provider.GetService(typeof(IA)) as A).methodA();
    }
}
public class C : IC
{
    private readonly IServiceProvider _provider;
    
    public C(IServiceProvider provider)
    {
        _provider = provider;
    }
    public int methodC()
    {
        return (_provider.GetService(typeof(IB)) as B).methodB();
    }
}

In startup:

services.AddTransient<IParameterService>(x => new ParameterService(1));
            services.AddTransient<IA,A>();
            services.AddTransient<IB,B>();
            services.AddTransient<IC, C>();

in controller:

    private readonly A _A;
    private readonly C _C;
    public SomeController(IServiceProvider provider)
    {
       
        _A = (A)provider.GetService(typeof(IA));
        _C=(C)provider.GetService(typeof(IC));
    }

Result:

enter image description here

Related