17

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?

8
  • How to register these services in startup ? Commented Jan 16, 2017 at 4:51
  • @Ahmar just the normal registration services.AddTransient<ISomeService, FooService>(); Commented Jan 16, 2017 at 4:58
  • Ok DI only resolve dependency those register with it. Other parameters not resolved. Commented Jan 16, 2017 at 5:10
  • 1
    ya, but is there anyway to achieve this? i need both registered dependency and values provided from client as shown in the question. Commented Jan 16, 2017 at 6:36
  • 1
    Google or search Stackoverflow for "abstract factory", got to leave for work can't find the reference on the quick Commented Jan 16, 2017 at 6:59

1 Answer 1

28

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.

Sign up to request clarification or add additional context in comments.

1 Comment

this answer turns out to be same as my implementation after i get the idea from @Tseng suggestions. thanks for posting this answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.