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?
To answer your question, there is no way. by definition, private constructors are inaccessible by other classes.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With