1

What are the advantages/disadvantages of the following approaches for injecting configuration information into a newly constructed instance? Which would you use?

interface IApplicationConfiguration {
    string SourcePath { get; }
    string DestinationPath { get; }
}

Option one:

class DailyFilePathProvider {
    private readonly string sourcePath;
    private readonly string destinationPath;
    public DailyFilePathProvider(string sourcePath, string destinationPath) {
        this.sourcePath = sourcePath;
        this.destinationPath = destinationPath;
    }
}

var configuration = container.Resolve<IApplicationConfiguration>();
var provider = new DailyFilePathProvider(configuration.SourcePath, configuration.DestinationPath);

Option two:

class DailyFilePathProvider {
    private readonly string sourcePath;
    private readonly string destinationPath;
    public DailyFilePathProvider(IApplicationConfiguration configuration) {
        this.sourcePath = configuration.SourcePath;
        this.destinationPath = configuration.DestinationPath;
    }
}

var configuration = container.Resolve<IApplicationConfiguration>();
var provider = new DailyFilePathProvider(configuration);

Thanks for all thoughts.

4 Answers4

1

It depends,

I would go for option two if IApplicationConfiguration only contains configuration related to the DailyFilePathProvider. If it contains configurations for other parts of your application you might consider this 'bad separation of concerns'. In that case a better option would be to add a property IDailyFilePathProviderCfg to the IApplicationConfiguration that contains configuration specifically for the DailyFilePathProvider. That way you get best of both worlds, you only inject relevant data like in option one but the code is also easy to maintain like in option two.

Personally I think application wide configuration is best abstracted away in a static class So all parts of the code can easily access settings.

The answer to this question depends a lot on personal programming style I guess. It also depends on the type and size of application you are building. Personally I don't like to inject more in a constructor than needed for the object you are building.

Jan
  • 8,011
  • 3
  • 38
  • 60
1

This answer of mine to a similar question may provide some insight:

Dependency Injection and AppSettings

The gist is that the Confguration interface is plumbing which adds no semantic value in the class that consumes it. There is also an example of how to structure an application so these values can easily be disseminated. The answer was marked as the question's accepted answer.

Community
  • 1
  • 1
Bryan Watts
  • 44,911
  • 16
  • 83
  • 88
0

I prefer option 2 so I can easily add more settings without changing the ctor. I would also switch it to...

class DailyFilePathProvider {
    private readonly IApplicationConfiguration configuration;
dotjoe
  • 26,242
  • 5
  • 63
  • 77
0

The first code only uses some kind of dependency injection to resolve which configuration to use, but it doesn't use dependency injection when constructing the DailyFilePathProvider.

So I would go for option number two where you actually are injecting the configuration into DailyFilePathProvider.

Here are some more about patterns with NInject as an example: Injection patterns

Tomas Jansson
  • 22,767
  • 13
  • 83
  • 137
  • 3
    Both are using dependency injection. You don't need an IoC container to do dependency injection. So in the first case, it looks like the OP is resolving the application configuration using a container, and then injecting the dependencies (`sourcePath` and `destinationPath`) manually, and in the second case, the OP is injecting a different dependency (`configuration`) manually. – jason Feb 11 '11 at 15:05
  • @Jason: I depends on what you are focusing on. Dependency injection is not used when creating the `DailyFilePathProvider` in the first example. It is used to resolve which configuration you are using, but nothing is injected when created the `DailyFilePathProvider`. – Tomas Jansson Feb 11 '11 at 15:09
  • @Jason I think this is somewhat a philosophical question. If you go with your example every object that has a constructor that takes parameters uses dependency injection. – Tomas Jansson Feb 11 '11 at 15:11
  • 2
    @Tomas Jansson: Yes, there are dependencies injected in the first example. The dependencies are strings, and they are injected via the constructor. – jason Feb 11 '11 at 15:21
  • @Tomas Jansson: It's not a philosophical question. Every class has dependencies. Those dependencies can be hidden by having `public Foo() { this.bar = new Bar(); }` in the constructor, or they can be injected via the constructor (so called "constructor injection") as in `public Foo(Bar bar) { this.bar = bar; }`. The latter is dependency injection, whether or not you use a container to resolve those dependencies. Your last sentence is exactly my point. The point of dependency injection is to make those dependencies explicit by putting them as parameters to the constructor. – jason Feb 11 '11 at 15:22
  • @Jason: As I see it the `SourcePath` and `DestinationPath` is not something the object depends on, it is a part of the object. So in the first example the properties are explicitly set and therefor I don't consider it a dependency. In the second example the properties are still part of the object but the object depends on a `IApplicationConfiguration` to get the values for them. Do you see the difference? I don't think you can depend on properties that defines the object (usually value types). Sometimes your properties are object with complex logic and in those cases you can have a dependency. – Tomas Jansson Feb 11 '11 at 15:31
  • 1
    @Thomas the object does depend on SourcePath and DestinationPath, that is why they are being set in the constructor. If they are optional, and only used in certain cases, then they wouldn't need to be sent into the constructor. Basically you depend on those values being sent to the class in order to make the class. Also, I don't see how it being a value or reference type means anything in this context. – Rangoric Feb 11 '11 at 15:38
  • @Tomas Jansson: `sourcePath` and `destinationPath` are dependencies. We could have the class read those values itself from some configuration file in its constructor. But that is bad, because it doesn't make the dependencies explicit, and it's a ridiculous violation of SRP. I don't know what you mean by "properties that define the object" but I suspect that you'll think that in `NormalDistribution(double mean, double variance)` both `mean` and `variance` are properties that define the object. I'll argue that `mean` and `variance` are dependencies. – jason Feb 11 '11 at 15:58
  • @Rangoric and @Jason: First off, interesting discussion :). I'm not meaning it has to be reference or value types, but I think value types are more common when it comes to defining the actual object. It's more about behavior. I'll try with analogy trying to make myself clearer. Let say you have an `Employee` class with two properties, `EmployeeName` and `Salary`. To get the `Salary` an `ISalaryCalculator` is used, and what I state is that the `EmployeeName` is "defining" the object but it also depend on some `ISalaryCalculator` through `Salary`, but that doesn't define the object. – Tomas Jansson Feb 11 '11 at 16:46