The best practice that I know of is to avoid direct dependency on app.config/web.config from classes in your library, or maybe even classes in general. That doesn't mean that you don't use app.config. It means that your classes don't know they're using it.
For example,
public class MyClassThatDependsOnSomeSettings
{
private readonly ISettings _settings;
public MyClassThatDependsOnSomeSettings(ISettings settings)
{
_settings = settings;
}
public void DoSomething()
{
var settingA = _settings.SettingA;
}
}
public interface ISettings
{
int SettingA {get;}
string SettingB {get;}
}
Now you can consider MyClassThatDependsOnSomeSettings
done. It doesn't require any access to a .config file. It just requires an instance of something that implements ISettings
. That can read from .config.
public class SettingsFromConfiguration : ISettings
{
public int SettingA
{
get
{
string setting = ConfigurationManager.AppSettings["settingA"];
int value = 0;
int.TryParse(setting, out value);
return value;
}
}
public string SettingB
{
get { return ConfigurationManager.AppSettings["settingB"];}
}
}
Does it look like this just moves things around and does the same thing anyway? It does, almost. The big difference is that while you can use an implementation of ISettings
that reads from app.config, you can also write other implementations. You can write one that uses hard-coded values, you could write a custom configuration section instead of using AppSettings
, or if down the road you have an application with a JSON configuration file and no AppSettings
your class can still work.
This applies the Dependency Inversion, which beneath everything means that classes should depend on abstractions (like interfaces) not concrete implementations.
Putting a requirement for ISettings
in the constructor is called Dependency Injection, specifically constructor injection.