Azure IoT Hub apps can require a number of configuration settings such as the IoTHubConnectionString. If they are all saved in-app in the one static class as its public properties it would be nice to use Refection to interrogate the class to get property names and values without explicit naming of the properties when saving and loading the setting to and from the app’s Local Settings. This article presents reusable methods for saving and reloading those settings to and from an app’s Local Settings.

I have a UWP app , AzDeviceStreamingApp, available in The Microsoft Store and as source on GitHub. The app streams data via an Azure IOT Hub between an IoT device and a user app. (The app can actually function as both ends of the pipe, and do this simultaneously.) The app requires a range of connection settings for connectivity to the IoT Hub such as Hub and Device Connection Strings and the DeviceId. The Hub’s inbuilt connectivity parameters are also required. The app stores these settings as string properties in a static class so that modules within the app have global access to these settings.

It is desirable to save these setting to the app’s local storage so that they can be reloaded when the app restarts. One could write code work through the specific properties in the class one-by-one and to save each as an individual name-vale pair in the apps’s local settings and to reverse that property-by-property process to load the values when reloaded. Wouldn’t it be nice to use something like Reflection to iterate through the static class’s properties in a non-class specific general manner? That is, use reflection to get property names without hardcoding their names. Also, having determined the property names of the class, how can you read the property values from the class and also to write them back without having the property names in explicit code. It would be nice to encapsulate these values into one entity to be saved as one item in the app’s Local Settings.

Don’t you just love StackOverflow for when you know what you want to do in code and just need some answers to existing relevant questions. Thankfully there are a couple of relevant gems on StackOverflow; one for iterating through the properties of a static class for setting and one for getting the property values in a general manner using Refection! Also Microsoft Docs covers Application Local Settings comprehensively, including for complex entities. This article presents a static class that has a method to store the app settings present in a static class as public properties and a method for reading the values back into the static class. Both methods use Reflection to get to the class’s properties, without specifically naming the properties. The class could be reused in any C# app requiring saving and reloading of app settings with just a change of the storage class.

So this issues discussed herein are:

(i) Application Settings saving and reloading (ii) How to iterate through the public property names of a static class just given the class. (iii) How to get and set property values as determined by (ii) (iv) Combining this to save and reload application settings stored as public properties of a static class.

Links

The StackOverFlow Gems

Oldies but goodies:

Microsoft Docs:

Application Data and LocalSettings

AzDeviceStreamingApp

Application Settings

You can save simple application data such as application settings to the app’s LocalSettings. This is a Dictionary of name-value pairs. For example:

keepDeviceListening = value;
Windows.Storage.ApplicationDataContainer localSettings =
Windows.Storage.ApplicationData.Current.LocalSettings;
if (localSettings.Values.Keys.Contains("KeepDeviceListening"))
{
    if (localSettings.Values["KeepDeviceListening"] is bool)
        localSettings.Values[\KeepDeviceListening"] = keepDeviceListening;
    else
        localSettings.Values.Remove("KeepDeviceListening");
}
if (!localSettings.Values.Keys.Contains("KeepDeviceListening"))
    localSettings.Values.Add("KeepDeviceListening", keepDeviceListening)

If a setting already exists in localsettings then you can just overwrite it. If it doesn’t you need to add it. Adding when it exists generates an error.

And it is a simple matter to recover the setting when the app is restarted or reset:

Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
if (localSettings.Values.Keys.Contains("KeepDeviceListening "))
{
    keepDeviceListening =(bool)localSettings.Values["KeepDeviceListening"];
}

These are data types you can use for app settings:

  • UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double
  • Boolean
  • Char16, String
  • DateTime, TimeSpan
  • GUID, Point, Size, Rect
  • ApplicationDataCompositeValue:

Composite Application Settings

Other data types have to be serialized into one of these data types for saving to LocalSettings. For example, a structured data type, a class with public properties, each property being of one of the above data types, might be serialized to a json string and that is saved to settings. Alternatively, a CompositeValue can be generated from a data type’s properties and that gets saved as representation of the original data. For example:

Given an instance IoTHubConnectionDetails of a class with a ConnectionString property:

Windows.Storage.ApplicationDataCompositeValue composite = new Windows.Storage.ApplicationDataCompositeValue();
composite["ConnectionString"] = IoTHubConnectionDetails.ConnectionString;

.. etc.

Then after similarly adding the other property values of IoTHubConnectionDetails to composite as name-value pairs, save composite to the LocalSettings:

localSettings.Values.Add("IoTHubConnectionDetails")= composite;

Upon app restart these values can then be recovered:

Windows.Storage.ApplicationDataCompositeValue composite = (Windows.Storage.ApplicationDataCompositeValue)localSettings.Values["IoTHubConnectionDetails"];
if (composite != null)
{
    if (composite.Keys.Contains("ConnectionString"))
        IoTHubConnectionDetails.ConnectionString = composite["ConnectionString"];
    //etc for other properties
}

So we map the properties of the class into a CompositeValue as name-value pairs. But how do we get the name-value pairs without naming the properties in “hard” code?

Using Reflection to get static classProperty Names and to get and set values therein.

“The System.Reflection namespace contains types that retrieve information about assemblies, modules, members, parameters, and other entities in managed code by examining their metadata.” Ref: System.Reflection-Microsoft Docs

Iteration

To iterate through the named static class and get the property names:

Type type = typeof(IoTHubConnectionDetails);
foreach (var property in type.GetProperties()
{
    string propertyName = property.Name;
    ...
    ...
}

Get property values

Insert in the loop above:

string propertyName = property.Name;
var val = property.GetValue(null); // static classes cannot be instanced, so use null\...
composite[propertyName] = val;

Set property values

Insert in the loop above

string propertyName = property.Name;
if (composite.Keys.Contains(propertyName))
{
    //Want to implement IoTHubConnectionDetails.propertyName = composite[propertyName];
    var propertyInfo = type.GetProperty(propertyName);
    propertyInfo.SetValue(type, composite[propertyName], null);
}

The Saving and Loading Application Property Methods

Save and load the public properties of a static class IoTHubConnectionDetails.
Source code for the following two methods on GitHub:Appsettings.cs

Saving Property Values

// Create a new instance of ApplicationDataCompositeValue object as composite
// Iterate through the properties of a static class and store each name-value pair in a composite
// Save that to the application\'s local settings as a name-value pair named ConDetail, replacing the existing object if it exists.
public static void SaveSettingsToAppData()
{
    Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
    if (localSettings.Values.Keys.Contains("ConDetail"))
    {
        localSettings.Values.Remove("ConDetail");
    }
    Windows.Storage.ApplicationDataCompositeValue composite = new Windows.Storage.ApplicationDataCompositeValue();

    Type type = typeof(IoTHubConnectionDetails); // IoTHubConnectionDetails is static class with public static properties
    foreach (var property in type.GetProperties())
    {
        string propertyName = property.Name;
        var val = property.GetValue(null); // static classes cannot be instanced, so use null\...
        composite[propertyName] = val;
    }
    localSettings.Values.Add("ConDetail ", composite);
}

Getting Property Values

// Load the ConDetails object from the application\'s local settings as an ApplicationDataCompositeValue instance.
// Iterate through the properties in the static class of current app settings, that are in a static class.
// If a property is in the ConDetails keys, assign the value for that key as in ConDetail, to the static class property.
public static void LoadConSettings()
{
    Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
    if (localSettings.Values.Keys.Contains("ConDetail"))
    {
        Windows.Storage.ApplicationDataCompositeValue composite =
                (Windows.Storage.ApplicationDataCompositeValue)localSettings.Values["ConDetail"];
        if (composite != null)
        {
            Type type = typeof(IoTHubConnectionDetails); // IoTHubConnectionDetails is static class with public static properties
            foreach (var property in type.GetProperties())
            {
                string propertyName = property.Name;
                if (composite.Keys.Contains(propertyName))
                {
                    //Want to implement Cons.propertyName = composite[propertyName];
                     var propertyInfo = type.GetProperty(propertyName);
                    propertyInfo.SetValue(type, composite[propertyName], null);
                }
            }
        }
   }
}

Footnotes

(i) In the code type.GetProperties() you can apply filters to the properties and fields of the class that are returned. For example:

type.GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public))

See Type.GetProperties() Method in Microsoft Docs.

(ii) It would be of value to use Generics with the methods. i.e.:

public static void SaveSettingsToAppData<T>() .. and ..
public static void LoadConSettings<T>()

But that isn’t possible with a static class.


 TopicSubtopic
<  Prev:   AziothubDeviceStreaming
   
 This Category Links 
Category:Application Dev Index:Application Dev
  Next: >  
<  Prev: