Wiki

Clone wiki

EasyAppSettings / Home

Easy AppSettings

Get this library on NuGet.

EasyAppSettings provides simple, strongly-typed access to AppSettings for .Net. Using interfaces or simple classes you define, this library will map hierarchical property names to AppSetting keys and deserialize the string value into concrete types using Json.NET.

Example

Let's say we have the following app settings.

<configuration>
  <appSettings>
    <add key="Example.AppMode" value="Console" />
    <add key="Example.Plugins" value="OpenDns,Aws.S3,Zencoder" />
    <add key="Example.Backup.TimeSinceLastBackup" value="4.08:32:00" />
    <add key="Example.Backup.Location" value="\\nas-01\backup" />
    <add key="Example.Backup.AdminPanelUrl" value="https://backups.example.com/" />
    <add key="Example.AppDirectory.Temp" value="c:\windows\temp" />
    <add key="Example.AppDirectory.Output" value="f:\myapp\output" />
  </appSettings>
</configuration>

And a unit test to check those values.

[Test]
public void CompareExampleAppSettings() 
{
  IExampleAppSettings appSettings = GetAppSettings(); // implementations below
  Assert.AreEqual(AppMode.Console, appSettings.AppMode);
  Assert.AreEqual("OpenDns,Aws.S3,Zencoder", appSettings.Plugins);
  Assert.AreEqual(new TimeSpan(4, 8, 32, 0), appSettings.Backup.TimeSinceLastBackup);
  Assert.AreEqual("\\nas-01\backup", appSettings.Backup.Location);
  Assert.AreEqual(new Uri("https://backups.example.com/"), appSettings.Backup.AdminPanelUrl);
  Assert.AreEqual("c:\windows\temp", appSettings.Directories.Temp);
  Assert.AreEqual("f:\myapp\output", appSettings.Directories.Output);
}

Automatic implementation

Inherit your interface from IGeneratedAppSettings to enable dynamic implementation generation.

public interface IExampleAppSettings : IGeneratedAppSettings 
{
  AppMode AppMode { get; }
  IEnumerable<string> Plugins { get; }
  IBackupSettings Backup { get; }
  [AppSetting(Key = "AppDirectory")] IDirectories Directories { get; }
}

public enum AppMode { Silent, Console, Gui, Service }

public interface IBackupSettings : IGeneratedAppSettings 
{
  TimeSpan TimeSinceLastBackup { get; }
  string Location { get; }
  Uri AdminPanelUrl { get; }
}

public interface IDirectories : IGeneratedAppSettings
{
  string Temp { get; }
  string Output { get; }
}

Use the AppSettingsGenerator to create an instance of your app settings interface.

public IExampleAppSettings GetAppSettings() 
{
  return AppSettingsGenerator.Default.CreateInstance<IExampleAppSettings>();
}

Manual implementation

Inherit from AppSettingsBase<> for access to convenience methods for getting app settings and automatic management of app setting key names and nested settings classes. When using manual implementation, you can override the naming convention and also provide a default value.

public class ExampleAppSettings : AppSettingsBase<ExampleAppSettings>
{
  public static ExampleAppSettings Default { get { return _default.Value; } }
  private static readonly Lazy<ExampleAppSettings> _default = new Lazy<ExampleAppSettings>(() => new ExampleAppSettings());

  public AppMode AppMode { get { Get(s => s.AppMode, AppMode.Service); } }
  public IEnumerable<string> Plugins { get { Get(s => s.Plugins, () => Plugins.GetDefaultPluginNames()); } }
  public BackupSettings Backup { get { Get(s => s.Backup); } }
  public Directories Directories { get { Get<Directories>("AppDirectory"); } }
}

public enum AppMode { Silent, Console, Gui, Service }

public class BackupSettings : AppSettingsBase<BackupSettings>
{
  public TimeSpan TimeSinceLastBackup { get { Get(s => s.TimeSinceLastBackup); } }
  public string Location { get { Get(s => s.Location); } }
  public Uri AdminPanelUrl { get { Get(s => s.AdminPanelUrl); } }
}

public class Directories : AppSettingsBase<Directories>
{
  public string Temp { get { Get(s => s.Temp); } }
  public string Output { get { Get(s => s.Output); } }
}

Simply create a new instance of your class. Nested app settings classes are created using Activator.CreateInstance.

public IExampleAppSettings GetAppSettings() 
{
  return new ExampleAppSettings();
  // or return ExampleAppSettings.Default;
}

AppSettings and ConnectionStrings

Interfaces are defined to wrap access to AppSettings and ConnectionStrings. Default singleton properties are provided. All types besides internal extension methods are open for paramaterization and extension.

public interface IAppSettings
{
    string this[string key] { get; }
    T Get<T>(string key);
    T Get<T>(string key, T defaultValue);
    T Get<T>(string key, Func<T> defaultValue);
}

public interface IConnectionStrings
{
    ConnectionStringSettings this[string key] { get; }
}

Environment

This library includes, and defaults to using, IEnvironment.Name and IEnvironment.Build to resolve app settings and connection strings. This feature is entirely optional and can be safely ignored in most situations.

The Name defaults to the computer name. The Build inspects the entry assembly and attempts to determine if it is a Debug, Release, or Test build. Both can be set in the app settings.

The most specific matching key is returned, with Name taking precedence over Build. The default separator can be changed.

<configuration>
  <appSettings>
    <add key="EasyAppSettings.Environment.Name" value="Staging" />
    <add key="EasyAppSettings.Environment.Build" value="Example" />
    <add key="Staging::Example.AppMode" value="Console" /> <!-- this value will be chosen with the above environment settings -->
    <add key="Example::Example.AppMode" value="Gui" />
    <add key="Staging::Release::Example.AppMode" value="Service" />
    <add key="AppMode" value="Silent" />
  </appSettings>
  <connectionStrings>
    <add name="Staging::Example::Conn1" connectionString="server=example.com" /> <!-- this value will be chosen with the above environment settings -->
    <add name="Staging::Conn1" connectionString="server=192.168.1.250:8080" />
    <add name="Conn1" connectionString="server=localhost" />
  </connectionStrings>
</configuration>
[Test]
public void CompareEnvironmentPrefixedSettings()
{
  var appSettings = AppSettingsGenerator.Default.CreateInstance<IAppSettings>();
  Assert.AreEqual(AppMode.Console, appSettings.AppMode);
  Assert.AreEqual("server=example.com", ConnectionStrings.Default["Conn1"].ConnectionString);
}

public interface IAppSettings : IGeneratedAppSettings
{
  AppMode AppMode { get; }
}

Setting value deserialization

Currently, the default serializer uses Json.NET. If the setting value is a simple value, the text is wrapped before being deserialized. Some customization is possible by constructing a NewtonsoftJsonDeserializer with your own JsonSerializer. Future road map includes plans to pass Json.NET attributes from your settings interfaces and classes to the internal serializer.

Updated