I'm new to Dependency Injection, and so in trying to implement it in my .net core 3.0 projects, I've run into a scenario where I need multiple instances of a single service registered in my Service Provider. As a workaround, I've resorted to injecting the IServiceProvider itself and just calling GetRequiredService<T> (of transient-scoped services) multiple times. That works, but appears to be an anti-pattern, and I'm not sure how I'm supposed to do it properly.
Part of the problem in researching this further is the insistence in every answer that the need for multiple instances of a single class is itself code smell, but as an example, let's say I'm providing instructions to an oven to automate the baking process. A user will define the temperatures and times for each recipe in a view, then the view will return a List<string> that represents that list of steps to the controller. A sample list of steps might look like:
//Bake for 500 degrees Fahrenheit for 30 minutes, then 225F for another 90
["500F,30","225F,90"]
I will then need to convert that to a List<CookingStep> in the controller to add to my Recipe object. I've been doing something like this:
IOven Oven;
IRecipe newRecipe;
IServiceProvider sp;
//public OvenController... (constructor with dependencies injected here)
public async Task<IActionResult> BakeSomething(List<string> steps)
{
foreach(string s in steps)
{
IRecipeStep recipeStep = sp.GetRequiredService<IRecipeStep>();
recipeStep.ParseTimeAndTemperatureFromString(s);
newRecipe.Steps.Add(recipeStep);
}
await Oven.Bake(newRecipe);
return View("RecipeComplete",newRecipe);
}
But that isn't really inversion of control and it doesn't make the code any more testable, so in researching best practices, I could do a factory pattern, but I'm not sure how that helps do anything but bury the ultimate instantiation in a different class.
So I can make a factory, even a generic one, but is this (admittedly overly simplistic example) really better than the service locator pattern above?
IOven Oven;
IRecipe newRecipe;
IRecipeStepFactory rsFactory;
//public OvenController... (constructor with dependencies injected here)
public async Task<IActionResult> BakeSomething(List<string> steps)
{
foreach(string s in steps)
{
IRecipeStep recipeStep = rsFactory.NewStepFromString(s);
newRecipe.Steps.Add(recipeStep);
}
await Oven.Bake(newRecipe);
return View("RecipeComplete",newRecipe);
}
public class RecipeStepFactory : IRecipeStepFactory
{
public IRecipeStep NewStepFromString(string s)
{
RecipeStep recipeStep = new RecipeStep();
recipeStep.ParseTimeAndTemperatureFromString(s);
return recipeStep;
}
}
(I apologize in advance for any issues with the presentation or substance of my question, it's the first time I've had to ask a question of my own)
sp? Does it have an interface?