XTOOLKIT
XTOOLKIT
Collection of utilities, helper classes and WPF controls

Managing User Settings using xToolkit


This service allows to manage user settings based on the JSON file with the support of backward compatibility.

Define the class which will be storing user settings:

[UserSettingVersion("1.0.0", typeof(UserSettingsVersionTransformer))]
public class UserSettings
{
    public string Field1 { get; set; }
    public double Field2 { get; set; }
    public bool Field3 { get; set; }
}

Call the code below to store the settings into an external file or stream

var svc = new UserSettingsService();

var userSetts = new UserSettings();

svc.StoreSettings(userSetts,
    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), 
    "my-app-settings.json"));

Settings are serialized using Newtonsoft.Json

In order to read the properties call the code below

var svc = new UserSettingsService();

var userSetts = svc.ReadSettings<UserSettings>(
    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "my-app-settings.json"));

Quite often it happens that properties structure needs to change (new properties are added, removed or renamed). But clients might already use previous version of the tool with an older settings structure. In this case deserialization of older properties will fail and the tool will not be considered backwards compatible and clients will need to reset the properties which will affect user experience.

This service takes care of this, allowing conversion of the properties.

As an example, let's consider that second version of the user settings declared above has the Field1 property renamed to TextField while the value of Field1 still represents the same entity and it is beneficial to support older properties.

[UserSettingVersion("2.0.0", typeof(UserSettingsVersionTransformer))]
public class UserSettings
{
    public string TextField { get; set; }
    public double Field2 { get; set; }
    public bool Field3 { get; set; }
}

Even more in the 3rd version of the settings two remaining properties will be renamed as per below.

[UserSettingVersion("3.0.0", typeof(UserSettingsVersionTransformer))]
public class UserSettings
{
    public string TextField { get; set; }
    public double DoubleField { get; set; }
    public bool BoolField { get; set; }
}

So it is now possible to have users with version 1, 2 and 3 of properties. They might upgrade with any of the following paths (if not using the latest version):

  • From version 1 to version 2
  • From version 2 to version 3
  • From version 1 to version 3

In order to handle this scenario it is possible to declare the transformer class and handle each individual version change transforming the JToken

public class UserSettingsVersionTransformer : BaseUserSettingsVersionsTransformer
{
    public UserSettingsVersionTransformer()
    {
        Add(new Version("1.0.0"), new Version("2.0.0"), t =>
        {
            var field1 = t.Children<JProperty>().First(p => p.Name == "Field1");
            field1.Replace(new JProperty("TextField", (field1 as JProperty).Value));
            return t;
        });

        Add(new Version("2.0.0"), new Version("3.0.0"), t =>
        {
            var field2 = t.Children<JProperty>().First(p => p.Name == "Field2");
            field2.Replace(new JProperty("DoubleField", (field2 as JProperty).Value));

            var field3 = t.Children<JProperty>().First(p => p.Name == "Field3");
            field3.Replace(new JProperty("BoolField", (field3 as JProperty).Value));

            return t;
        });
    }
}

It is only required to define the transformation between the closest version (i.e. 1 and 2, 2 and 3). It is not required to explicitly define the conversion from 1 to 3. If such conversion is required framework will firstly call the 1 to 2 conversion, followed by 2 to 3.


Powered by Docify