# Auto fill settings objects with .config values

**Date:** 2016-03-03  
**Author:** Kees C. Bakker  
**Categories:** .NET Framework / C#, KeesTalksTech Utility Pack  
**Original:** https://keestalkstech.com/auto-fill-settings-objects-with-config-values/

![Auto fill settings objects with .config values](https://keestalkstech.com/wp-content/uploads/2016/03/technology-music-sound-audio.jpg)

---

Lately I've been playing around with API's. Most of them need settings like AppId and AppSecret. I found myself doing the same work over and over again: creating a settings class, filling the class with information and using it. So I came up with a way to leverage reflection to fill my setting classes with **.config** values.

## Example class

A [CloudMQTT](https://www.cloudmqtt.com/docs.html) setting class could have the following properties:

```cs
public class MqttSettings
{
    [Required]
    public string BrokerHostName { get; set; }

    [Required]
    public uint Port { get; set; }

    [Required]
    public bool UseSecureConnection { get; set; }

    [Required]
    public string UserName { get; set; }

    [Required]
    public string Password { get; set; }

    [Required]
    public string Topic { get; set; }
}
```

So let's build something to automate the process! I would like it to be created and filled with the following line of C#:

```cs
var settings = AppSettingsProvider.Create<MqttClientSettings>();
```

## 1. Reading a setting from the configuration

So let's start with the basics, reading a setting from the config. I've created a static class with the basic ability to read a setting by its name. To access the `ConfigurationManager` you'll need to include a reference to the `System.Configuration`.

```cs
public static class AppSettingsProvider
{
    /// <summary>
    /// Gets the value of the setting from the configuration.
    /// </summary>
    /// <param name="key">The name of the setting.</param>
    /// <param name="required">If <c>true</c> an exception will be thrown if the setting isn't present.</param>
    /// <returns>The value.</returns>
    public static string GetValue(string key, bool required = true)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        string value = ConfigurationManager.AppSettings[key];

        if (required && String.IsNullOrWhiteSpace(value))
        {
            throw new Exception("Required configuration value for '" + key + "' is missing. Add it to config.");
        }

        return value;
    }
}
```

Some settings will be required. The system should throw an error if a configuration value is missing. The exception will inform the end-user about what setting is missing in the configuration file.

**Note: **I'm using a *String.IsNullOrWhiteSpace* check to see if a settings has been filled. You might want to see if this fits your needs. A value with only spaces or an empty string might be something you want to support.

## 2. Get a value by convention

To make the system easier to work, a convention for configuration-names is needed. I'm using `{namespace}.{class-name}.{field-name}`. My config file will look like this:

```cs
<add key="KeesTalksTech.Apis.Mqtt.MqttClientSettings.BrokerHostName" 
     value="m88.cloudmqtt.com" />

<add key="KeesTalksTech.Apis.Mqtt.MqttClientSettings.Port"
     value="21337" />

<add key="KeesTalksTech.Apis.Mqtt.MqttClientSettings.UseSecureConnection"
     value="true" />

<add key="KeesTalksTech.Apis.Mqtt.MqttClientSettings.UserName"
     value="6hhmsd33daas" />

<add key="KeesTalksTech.Apis.Mqtt.MqttClientSettings.Password"
     value="-tdERffsd3#4" />
```

To make things more convenient, I have to add a method that resolves the configuration name and value for a given object and field:

```cs
/// <summary>
/// Gets the value for the field of an object from the configuration. 
/// The classname of the object is used to construct the setting name.
/// </summary>
/// <param name="obj">The object.</param>
/// <param name="field">The name of the field.</param>
/// <param name="required">If <c>true</c> an exception will be thrown if the setting isn't present.</param>
/// <returns>The value.</returns>
public static string GetValue(object obj, string field, bool required = true)
{
    if (obj == null)
    {
        throw new ArgumentNullException(nameof(obj));
    }

    if (field == null)
    {
        throw new ArgumentNullException(nameof(field));
    }

    string settingName = obj.GetType().FullName + "." + field;

    //fix inner classes
    settingName = settingName.Replace("+", ".");

    return GetValue(settingName, required);
}
```

This solution supports inner classes. Generic classes aren't supported (as the `GetType().FullName` returns a weird looking name).

## 3. Fill settings object

Any object can be filled by configuration values, so let's create a method that takes an object and inspect its properties using reflection. All instance properties that are public and settable will qualify. I'm using the standard [`System.ComponentModel.DataAnnotations.RequiredAttribute`](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute(v=vs.110).aspx) to determine if the field is required. To convert the string value to the right destination type I'm using a [`Convert.ChangeType`](https://msdn.microsoft.com/en-us/library/dtb69x08(v=vs.110).aspx).

```cs
/// <summary>
/// Fills the public settable instance properties with the corresponding configuration values. 
/// Properties decorated with [Required] will throw an error if they aren't set by the configuration.
/// </summary>
/// <param name="obj">The object. Required.</param>
public static void Fill(object obj)
{
    if (obj == null)
    {
        throw new ArgumentNullException(nameof(obj));
    }

    var properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance);

    foreach (var property in properties)
    {
        var required = property.GetCustomAttribute<RequiredAttribute>() != null;
        var value = GetValue(obj, property.Name, required);

        if (!String.IsNullOrEmpty(value))
        {
            object convertedValue = Convert.ChangeType(value, property.PropertyType);
            property.SetValue(obj, convertedValue);
        }
    }
}
```

**Note: **I'm rejecting (not binding) values that are null or "". You might need something different in your project.

## 4. Convenience: create a settings object

I love generics, so I added one more convenience method:

```cs
/// <summary>
/// Creates the object and fills it with values from the configuration. 
/// The public settable instance properties with the corresponding 
/// configuration values. Properties decorated with [Required] will
/// throw an error if they aren't set by the configuration.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <returns>An instance with filled properties.</returns>
public static T Create<T>() where T : new()
{
    var config = new T();
    Fill(config);
    return config;
}
```

## Fill 'er up!

So let's see how this works together in a factory pattern. Line *10* loads creates a filled settings object:

```cs
using KeesTalksTech.Apis.Mqtt.M2MQTT;
using KeesTalksTech.Utilities;

public static class MqttClientFactory
{
    public static IMqttClient CreateClient()
    {
        var settings = AppSettingsProvider.Create<MqttClientSettings>();
        return CreateClient(settings);
    }

    public static IMqttClient CreateClient(MqttClientSettings settings)
    {
        return new M2MqttAdapter(settings);
    }
}
```

With a solution like this, loading settings becomes way easier. As your APIs increase, your settings in your config will remain manageable and readable.

## GitHub

Want to use this solution? Great. You can find it here on GitHub: `AppSettingsProvider`.

## NuGet

Or just NuGet it into your project:

```shell
dotnet add package KeesTalksTech.Utilities.Settings --version 0.3.2
```
