Chai Wei Jian
Chai Wei Jian

Reputation: 173

.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?

Upvotes: 17

Views: 19221

Answers (1)

MindingData
MindingData

Reputation: 12460

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.

Upvotes: 28

Related Questions