Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net core dependency injection with parameters on constructor

In .net core, if I use dependency injection is it true that all the constructor parameters must be provide by DI?

Let's say:

public Person CreateClient()
{
    string phone = "12345678";
    return new Person(phoneNumber: phone);        
}

public class Person 
{
    private readonly ISomeService _service;
    private readonly string _phoneNumber;
    public Person (ISomeService service, string phoneNumber)
    {
        _service = service;
        _phoneNumber = phoneNumber;
    }

    public string PhoneNumber {get { return _phoneNumber; } }
    public string Gender {get { return _service.GetGenderFromDb(); } }
}

public interface ISomeService
{
    String GetGenderFromDb();
}

public class FooService : ISomeService
{
    public String GetGenderFromDb() { return "Male"; }
}

Is this possible for DI and value provided by client to stay in same constructor?

like image 261
Chai Wei Jian Avatar asked Jan 16 '17 04:01

Chai Wei Jian


People also ask

Can you inject dependency through private constructor?

To answer your question, there is no way. by definition, private constructors are inaccessible by other classes.

Can we have MVC controller with parameterized constructor?

Simply framework will fail to create those controllers object that have parameterized constructor. In that case we need to create controller objects by our self and inject controller parameters there.

What is IServiceCollection in .NET Core?

IServiceCollection is the collection of the service descriptors. We can register our services in this collection with different lifestyles (Transient, scoped, singleton) IServiceProvider is the simple built-in container that is included in ASP.NET Core that supports constructor injection by default.


1 Answers

Anywhere where you are calling "new" to create an object isn't great for doing constructor DI from top to bottom. DI isn't suitable when you want to pass in parameters into constructors.

As others have alluded to, the best way is to create a factory. It might look something like this.

public class Person 
{   
    private readonly ISomeService _service;
    private readonly string _phoneNumber;
    public Person (ISomeService service, string phoneNumber)
    {
        _service = service;
        _phoneNumber = phoneNumber;
    }

    public string PhoneNumber {get { return _phoneNumber; } }
    public string Gender {get { return _service.GetGenderFromDb(); } }
}

public class PersonFactory : IPersonFactory
{
    private readonly ISomeService _someService;

    public PersonFactory(ISomeService someService)
    {
        _someService = someService;
    }

    public GetPerson(string phoneNumber)
    {
        return new Person(_someService, phoneNumber);
    }
}

Now when you want to create a person, instead you would inject in an instance of IPersonFactory, and call GetPerson on it.

Furthermore, you may find that you want your models to be more plain and the factory to do most of the heavy lifting. I see that Gender is coming from the database at the moment, so you may change it to look more like the following :

public class Person 
{   
    public Person (string gender, string phoneNumber)
    {
        Gender = gender;
        PhoneNumber = phoneNumber;
    }

    public string PhoneNumber {get; private set; }
    public string Gender {get; private set;}
}

public class PersonFactory : IPersonFactory
{
    private readonly ISomeService _someService;

    public PersonFactory(ISomeService someService)
    {
        _someService = someService;
    }

    public GetPerson(string phoneNumber)
    {
        var gender = _someService.GetGenderFromDb();
        return new Person(gender, phoneNumber);
    }
}

Now your Person class doesn't have any details about where it gets a Gender from, and the factory works out how to create a Person model each time.

like image 76
MindingData Avatar answered Sep 23 '22 10:09

MindingData