skip to Main Content

If I put this code in a 3rd party library I’m building.

public class AsyncDb2Read
{
    private readonly DB2Connection connection;

    public AsyncDb2Read()
    {
        var assembly = System.Reflection.Assembly.GetEntryAssembly();
        var c = new ConfigurationBuilder()
        .AddUserSecrets(assembly, true)
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .Build();
        string connectionString = c.GetConnectionString("DB2ConnectString")!;
        connection = new DB2Connection(connectionString);
        connection.SystemNaming = true;
    }

My question is: will it introduce any strange behavior in the consuming application since we are running IConfiruation‘s .Build() against the configuration root more than once?

If so, is there a way to consume the parent projects settings from within a 3rd party library without jeopardizing the configuration root?

2

Answers


  1. I wouldn’t risk it in your place. You are essentially creating multiple instances of the configuration. If the consumer application has already created a configuration root, your library build process can override the existing configuration, which will likely result in undefined behavior.

    Why can’t you just pass to the constructor IConfiguration created on the other side just already configured?

    if I’ve got this right, you could just do it like this:

    public class AsyncDb2Read
    {
        private readonly DB2Connection connection;
    
        public AsyncDb2Read(IConfiguration c)
        {
            string connectionString = 
            c.GetConnectionString("DB2ConnectString")!;
            connection = new DB2Connection(connectionString);
            connection.SystemNaming = true;
        }
    }
    

    and there just paste the code with settings:

    var assembly = System.Reflection.Assembly.GetEntryAssembly();
    var configuration = new ConfigurationBuilder()
       .AddUserSecrets(assembly, true)
       .SetBasePath(Directory.GetCurrentDirectory())
       .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
       .Build();
    var asyncDb2Read = new AsyncDb2Read(configuration);
    
    Login or Signup to reply.
  2. It’s hardly a good idea to take such a tight dependency on a particular configuration system. It bears similarities with the old Provider (anti)pattern.

    It looks as though the AsyncDb2Read class needs a DB2Connection. If so, pass it via the constructor:

    public class AsyncDb2Read
    {
        private readonly DB2Connection connection;
    
        public AsyncDb2Read(DB2Connection connection)
        {
            this.connection = connection;
        }
    

    The class doesn’t need an IConfiguration object. It only needs DB2Connection, so pass only that object. This follows from Nikola Malovic’s 4th law of IoC:

    "Every constructor of a class being resolved should not have any implementation other then accepting a set of its own dependencies."

    Inversion Of Control, Single Responsibility Principle and Nikola’s laws of dependency injection, Nikola Malovic, 2009

    You can wire up the DB2Connection object in your application’s Composition Root. This gives you (or another client developer) the flexibility to use IConfiguration, if that’s what you want, or another configuration system if such a need should arise.

    Since you’re creating a 3rd-party library, you can’t (or shouldn’t) make any assumptions about the context in which client developers will be using the library.

    You can read more in DI-Friendly Library.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search