Comments on: .NET Dependency Injection With Constructor Parameters https://code-maze.com/dotnet-using-constructor-injection/ Learn. Code. Succeed. Fri, 17 Feb 2023 04:41:25 +0000 hourly 1 https://wordpress.org/?v=6.7.5 By: Marinko Spasojević https://code-maze.com/dotnet-using-constructor-injection/#comment-7545 Fri, 17 Feb 2023 04:41:25 +0000 https://code-maze.com/?p=81623#comment-7545 In reply to Larry S.

Oh, thank you. I got it now. Thank you for the clarification and the example.

]]>
By: Larry S https://code-maze.com/dotnet-using-constructor-injection/#comment-7544 Fri, 17 Feb 2023 02:53:36 +0000 https://code-maze.com/?p=81623#comment-7544 In reply to MarinkoSpasojevic.

I think you misunderstood my point, sorry if I wasn’t clearer…but I’m not arguing against using the IOptions pattern at all, I’m merely saying your AnimalSoundService class should not have to have any knowledge of (ie dependency on) IOptions, as it is a detail of your host model’s configuration capabilities and not of the AnimalSoundService.

Here your service’s constructor takes an IOptions<CowOptions> parameter, so your service needs to take a dependency on IOptions:

public AnimalSoundService(IDogSoundService dogSoundService,
  IConfiguration configuration,
  IOptions<CowOptions> options)
{
  AnimalSounds = new List<string>()
  {
    dogSoundService.GetSound(),
    configuration[“CatSound”],
    options.Value.CowSound
  };
}

And here is how your DI container instantiates your service and passes in configuration via IOptions<CowOptions>:

services.AddScoped<IAnimalSoundService, AnimalSoundService>(
  serviceProvider => new AnimalSoundService(
      dogSoundService: serviceProvider.GetRequiredService<IDogSoundService>(),
      configuration: serviceProvider.GetRequiredService<IConfiguration>(),
      options: serviceProvider.GetRequiredService<IOptions<CowOptions>>(),
      sheepSound: “Baa”)
  );

My point is that you should remove the IOptions dependency from your service by changing the constructor to accept the “raw” CowOptions class:

public AnimalSoundService(IDogSoundService dogSoundService,
  IConfiguration configuration,
  CowOptions options)
{
  AnimalSounds = new List<string>()
  {
    dogSoundService.GetSound(),
    configuration[“CatSound”],
    options.CowSound
  };
}

but you can still use the IOptions pattern and get the ease of configuration it provides by changing the AddScoped method’s lambda to use the Value property of the result of the serviceProvider.GetRequiredService<IOptions<CowOptions>>() call to pass the actual CowOptions object to the service’s constructor:

services.AddScoped<IAnimalSoundService, AnimalSoundService>(
  serviceProvider => new AnimalSoundService(
      dogSoundService: serviceProvider.GetRequiredService<IDogSoundService>(),
      configuration: serviceProvider.GetRequiredService<IConfiguration>(),
      options: serviceProvider.GetRequiredService<IOptions<CowOptions>>().Value,
      sheepSound: “Baa”)
  );

Now that you’ve removed the IOptions dependency from the AnimalSoundService class by replacing IOptions<CowOptions> with just CowOptions, the service can be used in any environment where you may not have the same IOptions functionality available

]]>
By: MarinkoSpasojevic https://code-maze.com/dotnet-using-constructor-injection/#comment-7531 Thu, 16 Feb 2023 07:05:25 +0000 https://code-maze.com/?p=81623#comment-7531 In reply to Larry S.

Hi Larry. Thank you for the comment. To be honest, I always used the IOptions pattern to extract configuration values and that would always be my first recommendation. This is exactly what we stated here if you want to extract values from the configuration, which is a quite common case. You can do your way as well, of course. Developers should choose what fits the best for their use case. Your comment is here, so if anyone likes that idea, they can use it.

]]>
By: Larry S https://code-maze.com/dotnet-using-constructor-injection/#comment-7529 Wed, 15 Feb 2023 23:51:11 +0000 https://code-maze.com/?p=81623#comment-7529 Using the Options pattern as you did now means your AnimalSoundsService has to take a dependency on IOptions and hence pollutes it’s parameters list and minimizes the other scenarios that service could be used.

It would be better to just use the CowOptions directly in your AnimalSoundsService constructor instead of IOptions<CowOptions>. You would then need to change the lambda in the services.AddScoped call to use the Value property of the result of GetRequiredService<IOptions<CowOptions>>() to pass the CowOptions object into the constructor.

The same applies to using IConfiguration.

It’s a better separation of concerns to require the hosting environment (ie. ASP.NET in this case) to know how to pull information out of its configuration system and stuff it into CowOptions versus making your AnimalSoundsService tightly coupled to that particular configuration environment.

]]>
By: Marinko Spasojević https://code-maze.com/dotnet-using-constructor-injection/#comment-7521 Tue, 14 Feb 2023 07:50:55 +0000 https://code-maze.com/?p=81623#comment-7521 In reply to Rob Slaney.

Thank you Rob for the comment. Also, if you have time, any example would be appreciated (just to be sure that we are on the same page), and we can even link it to the article.

]]>
By: Rob Slaney https://code-maze.com/dotnet-using-constructor-injection/#comment-7517 Tue, 14 Feb 2023 01:09:24 +0000 https://code-maze.com/?p=81623#comment-7517 That last version ( using the factory with all the GetRequiredServices ) can be accomplished using ActivatorUtilities.CreateInstance. It will resolve the remaining parameters not supplied. However caution needs to be advised here as you could inject Transient instances into Scoped which would normally be disallowed.

]]>