3

When I have nested classes where children need some of the configuration settings (i.e., settings written in appsettings.json), do I need to make a bucket relay to pass configuration to children classes?

I don't think the example below is a smart way. Is there any better practice?

Startup.cs

public Startup(IConfiguration configuration, ...)
    {
        ...
        this.Configuration = configuration;
        ...
    }

Parent.cs

public class Parent
{
    public Parent(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    private IConfiguration _configuration;
    private ChildOne _childOne;
    private ChildTwo _childTwo;

    public void InitializeChildren()
    {
        _childOne = new ChildOne(_configuration);
        _childTwo = new ChildTwo(_configuration);
    }
}

ChildOne.cs

public class ChildOne{
    public ChildOne(IConfiguration configuration){
        _propOne = configuration.GetSection("brahbrah").Value;
    }

    private string _propOne;
}
2
  • Where does your term bucket relay, in programming terms, originate from? Commented Feb 7, 2019 at 11:28
  • It's my facile translation of "バケツリレー" in Japanese :D, which is oftentimes referred to when people explain how to handle the props in React framework. Commented Feb 7, 2019 at 11:37

2 Answers 2

2

Domain objects / models are nothing more than data containers. These data containers can have a need for data but should not be dependent on dependency injection (directly) for this data because they are at the core of your application. A change in your model (or it's dependencies) will most likely result in bigger changes.

As you show in your examples you want to instantiate your models using the new operator and pass the IConfiguration as a parameter. By requiring IConfiguration in your data container you create a situation where your model will need extensive checking if the returned result exists and if every property in it exists and afterward setting the appropriate values in the data container.

A better solution to this problem is by registering a dedicated config class, which we will call BrahBrahConfig to match your example, in the dependency injection framework.

public static IServiceCollection SetupDependencyInjection(this 
    IServiceCollection services, IConfiguration config)
{
    services.Configure<BrahBrahConfig>(config.GetSection("brahbrah"));

    return services;
}

In the example above you see the use of an overload for IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration config) which can be found in the nuget package "Microsoft.Extensions.Options.ConfigurationExtensions".

This overload enables you to directly inject an instance of IOptions into the constructor of your choice.

private BrahBrahConfig _config;

public Parent(IOptions<BrahBrahConfig> config)
{
    _config = config?.Value ?? throw new ArgumentNullException(nameof(config));
}

So after registering this in your startup.cs you can use IOptions as parameter in the Parent constructor and use these settings to set the appropriate properties in your model.

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

5 Comments

It seems a good alternative, let me take a look at it. Thanks for your info.
To extend upon @simonare's question. I also believe that models should not be injected with anything. I believe that the creating class should initialize these models. But the method on how to retrieve the necessary configuration would be exactly as I described but the injection would be on a different constructor.
Umm I'm not sure if I understand the concept correctly... Could you please edit your answer and clarify it if you don't mind?
@K.Makino I edited my answer to hopefully explain the concepts better and give some better examples
Now it seems clear, thanks for your update! Indeed I found that the nuget package is included in the latest .net core sdk so that I may consider go this option.
1

Use dependency injection for your services, not for your Models. Models should not have any logic or service registration.

If you are talking about Service Classes, they are generally part of DI. you can register them to DI so that DI automatically resolves services upon instance construction.

For Instance,

public class Parent
{
    public Parent(IConfiguration configuration, ChildOne childOne, ChildTwo childTwo)
    {
        _configuration = configuration;
        _childOne = childOne;
        _childTwo = childTwo;
    }

    private IConfiguration _configuration;
    private ChildOne _childOne;
    private ChildTwo _childTwo;

}

If you need to initialize ChildOne and ChildTwo by yourself, then you need to pass IConfiguration parameter or at least IServiceProvider in order to resolve required service(s)

3 Comments

In my case I'd have children initialized by myself, then I should pass the configuration parameter to them, right?
Even when using your example, how would _childOne be able to access _configuration ? It would always need to get a reference to the _configuration object in order to access it.
With this approach I believe the parent should be in charge of setting the necessary properties, not the children themselves.

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.