Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways of keeping configuration code out of logic code using Dependency Injection

How can keep all the configuration file code out of my logic code using Settings (ApplicationSettingsBase) and Dependency Injection?

With configuration I mean a customer specific configuration file.

Do I really have to inject a configuration class everytime I need it or is there another pattern?

It would be great to get some sample code!

Samples:

Static Configuration:

public static class StaticConfiguration {     public static bool ShouldApplySpecialLogic { get; set; }     public static string SupportedFileMask { get; set; } }  public class ConsumerOfStaticConfiguration {     public void Process()     {         if (StaticConfiguration.ShouldApplySpecialLogic)         {             var strings = StaticConfiguration.SupportedFileMask.Split(',');             foreach (var @string in strings)             {              }         }     } } 

Non static Configuration:

public interface IConfiguration {     bool ShouldApplySpecialLogic { get; set; }     string SupportedFileMask { get; set; } }  public class Configuration : IConfiguration {     public bool ShouldApplySpecialLogic { get; set; }     public string SupportedFileMask { get; set; } }  public class Consumer {     private readonly IConfiguration _configuration;      public Consumer(IConfiguration configuration)     {         _configuration = configuration;     }      public void Process()     {         if (_configuration.ShouldApplySpecialLogic)         {             var strings = _configuration.SupportedFileMask.Split(',');             foreach (var @string in strings)             {              }         }     } } 

Static Context with non static configuration:

public static class Context {     public static IConfiguration Configuration { get; set; } }  public class ConsumerOfStaticContext {     public void Process()     {         if (Context.Configuration.ShouldApplySpecialLogic)         {             var strings = Context.Configuration.SupportedFileMask.Split(',');             foreach (var @string in strings)             {              }         }     } } 
like image 689
Rookian Avatar asked Sep 02 '11 20:09

Rookian


People also ask

How many ways can dependency injection be done?

There are three types of dependency injection — constructor injection, method injection, and property injection.

What is the right way to inject dependency?

Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed. By using the guard pattern, you can use the class with confidence, knowing that the field variable storing that dependency will be a valid instance.


2 Answers

Configuration classes reduce cohension and increase coupling in the consumers. This is because there may be many settings that don't relate to the one or two needed by your class, yet in order to fulfill the dependency, your implementation of IConfiguration must supply values for all of the accessors, even the irrelevant ones.

It also couples your class to infrastructure knowledge: details like "these values are configured together" bleed out of the application configuration and into your classes, increasing the surface area affected by changes to unrelated systems.

The least complex, most flexible way to share configuration values is to use constructor injection of the values themselves, externalizing infrastructure concerns. However, in a comment on another answer, you indicate that you are scared of having a lot of constructor parameters, which is a valid concern.

The key point to recognize is that there is no difference between primitive and complex dependencies. Whether you depend on an integer or an interface, they are both things you don't know and must be told. From this perspective, IConfiguration makes as much sense as IDependencies. Large constructors indicate a class has too much responsibility regardless of whether the parameters are primitive or complex.

Consider treating int, string and bool like you would any other dependency. It will make your classes cleaner, more focused, more resistant to change, and easier to unit test.

like image 109
Bryan Watts Avatar answered Sep 28 '22 04:09

Bryan Watts


The important part to realize is that configuration is only one among several sources of values that drive your application's behavior.

The second option (non-static configuration) is best because it enables you to completely decouple the consumer from the source of the configuration values. However, the interface isn't required, as configuration settings are normally best modeled as Value Objects.

If you still want to read the values from a configuration file, you can do that from the application's Composition Root. With StructureMap, it might looks something like this:

var config = (MyConfigurationSection)ConfigurationManager.GetSection("myConfig");  container.Configure(r => r     .For<Consumer>()     .Ctor<MyConfigurationSection>()     .Is(config)); 
like image 21
Mark Seemann Avatar answered Sep 28 '22 03:09

Mark Seemann