Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core Dependency Injection how to handle multiple objects

As the title says I have a .NET Core application that I am trying to convert over to and take advantage of the built in Microsoft Dependency Injection.

I have an object and a base class for the object, call it CommunicationBase and Communicator. When my app starts up and reads the configuration file, I can have N number of objects to instantiate.

Previously, before switching to Dependency Injection, somewhere in my startup routine, where I read the configuration file, I would have a List<CommunicationBase> variable that I would instantiate and add Communicator objects to and at the same time, set some of the base properties, which changed based on how many were in my configuration and each ones properties in config.

How would I achieve this with DI?

I understand that in my services, I would register the type so it can be injected into other class constructors.

For example, services.AddTransient<CommunicationBase, Communicator>(); but as I understand it, this just registers the types with DI. I can inject it into a class and have a random instance of one of them.

How would I then have N number of instances and be able to set properties of each one as I create the instance?

Or, is this a scenario where DI is not necessary or won't work and I need to just do it the way I was doing it before?

Thanks!

like image 705
Michael Bedford Avatar asked Oct 27 '22 09:10

Michael Bedford


1 Answers

I would slightly modify approach shown here. So I would define some enum that would then be used to decide what instance to return.

Sample classes setup and the enum:

public enum CommuniationType
{
    False, True, Other,
}

public abstract class CommunicationBase
{
    public CommunicationBase(CommuniationType communiationType)
    {
        CommuniationType = communiationType;
    }

    public bool IsConnected { get; set; }
    
    public CommuniationType CommuniationType { get; protected set; }
}

public class Communicator : CommunicationBase
{
    public Communicator(CommuniationType communiationType) : base(communiationType) { }
}

Now, in the place where you have access to service collection (e.g. in ASP.NET the place would be Stratup.RegisterServices method) you define your objects of concrete class and register them, as in the sample code below (at the bottom, there are also test classes using CommunicationBase object for testing puproses):

public class Program
{
    static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        
        SetupNObjects(serviceCollection);

        serviceCollection.AddTransient<CommunicationBaseServiceResolver>(serviceProvider => communicationType =>
        {
            var implementations = serviceProvider.GetServices<CommunicationBase>();
            return implementations.First(x => x.CommuniationType == communicationType);
        });

        serviceCollection.AddScoped<FalseTestClass>();
        serviceCollection.AddScoped<TrueTestClass>();

        var serviceProvider = serviceCollection.BuildServiceProvider();

        var f = serviceProvider.GetService<FalseTestClass>();
        var t = serviceProvider.GetService<TrueTestClass>();
    }
    
    // Here you should take care of registering objects, after reading config.
    // That would be best place to do that.
    static void SetupNObjects(ServiceCollection serviceCollection)
    {
        var comFalse = new Communicator(CommuniationType.False);
        comFalse.IsConnected = false;

        var comTrue = new Communicator(CommuniationType.True);
        comTrue.IsConnected = true;

        serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comFalse);
        serviceCollection.AddScoped<CommunicationBase>((serviceProvider) => comTrue);
    }
}

public class FalseTestClass
{
    private readonly CommunicationBase communication;

    public FalseTestClass(CommunicationBaseServiceResolver resolver)
    {
        communication = resolver(CommuniationType.False);
    }
}

public class TrueTestClass
{
    private readonly CommunicationBase communication;
    
    public TrueTestClass(CommunicationBaseServiceResolver resolver)
    {
        communication = resolver(CommuniationType.True);
    }
}
like image 153
Michał Turczyn Avatar answered Nov 15 '22 05:11

Michał Turczyn