Configuration Management

Note

This eBook was published in the spring of 2017, and has not been updated since then. There is much in the book that remains valuable, but some of the material is outdated.

Settings allow the separation of data that configures the behavior of an app from the code, allowing the behavior to be changed without rebuilding the app. There are two types of settings: app settings, and user settings.

App settings are data that an app creates and manages. It can include data such as fixed web service endpoints, API keys, and runtime state. App settings are tied to the existence of the app and are only meaningful to that app.

User settings are the customizable settings of an app that affect the behavior of the app and don't require frequent re-adjustment. For example, an app might let the user specify where to retrieve data from, and how to display it on the screen.

Xamarin.Forms includes a persistent dictionary that can be used to store settings data. This dictionary can be accessed using the Application.Current.Properties property, and any data that's placed into it is saved when the app goes into a sleep state, and is restored when the app resumes or starts up again. In addition, the Application class also has a SavePropertiesAsync method that allows an app to have its settings saved when required. For more information about this dictionary, see Properties Dictionary.

A downside to storing data using the Xamarin.Forms persistent dictionary is that it's not easily data bound to. Therefore, the eShopOnContainers mobile app uses the Xam.Plugins.Settings library, available from NuGet. This library provides a consistent, type-safe, cross-platform approach for persisting and retrieving app and user settings, while using the native settings management provided by each platform. In addition, it's straightforward to use data binding to access settings data exposed by the library.

Note

While the Xam.Plugin.Settings library can store both app and user settings, it makes no distinction between the two.

Creating a Settings Class

When using the Xam.Plugins.Settings library, a single static class should be created that will contain the app and user settings required by the app. The following code example shows the Settings class in the eShopOnContainers mobile app:

public static class Settings  
{  
    private static ISettings AppSettings  
    {  
        get  
        {  
            return CrossSettings.Current;  
        }  
    }  
    ...  
}

Settings can be read and written through the ISettings API, which is provided by the Xam.Plugins.Settings library. This library provides a singleton that can be used to access the API, CrossSettings.Current, and an app's settings class should expose this singleton via an ISettings property.

Note

Using directives for the Plugin.Settings and Plugin.Settings.Abstractions namespaces should be added to a class that requires access to the Xam.Plugins.Settings library types.

Adding a Setting

Each setting consists of a key, a default value, and a property. The following code example shows all three items for a user setting that represents the base URL for the online services that the eShopOnContainers mobile app connects to:

public static class Settings  
{  
    ...  
    private const string IdUrlBase = "url_base";  
    private static readonly string UrlBaseDefault = GlobalSetting.Instance.BaseEndpoint;  
    ...  

    public static string UrlBase  
    {  
        get  
        {  
            return AppSettings.GetValueOrDefault<string>(IdUrlBase, UrlBaseDefault);  
        }  
        set  
        {  
            AppSettings.AddOrUpdateValue<string>(IdUrlBase, value);  
        }  
    }  
}

The key is always a const string that defines the key name, with the default value for the setting being a static readonly value of the required type. Providing a default value ensures that a valid value is available if an unset setting is retrieved.

The UrlBase static property uses two methods from the ISettings API to read or write the setting value. The ISettings.GetValueOrDefault method is used to retrieve a setting's value from platform-specific storage. If no value is defined for the setting, its default value is retrieved instead. Similarly, the ISettings.AddOrUpdateValue method is used to persist a setting's value to platform-specific storage.

Rather that define a default value inside the Settings class, the UrlBaseDefault string obtains its value from the GlobalSetting class. The following code example shows the BaseEndpoint property and UpdateEndpoint method in this class:

public class GlobalSetting  
{  
    ...  
    public string BaseEndpoint  
    {  
        get { return _baseEndpoint; }  
        set  
        {  
            _baseEndpoint = value;  
            UpdateEndpoint(_baseEndpoint);  
        }  
    }  
    ...  

    private void UpdateEndpoint(string baseEndpoint)  
    {  
        RegisterWebsite = string.Format("{0}:5105/Account/Register", baseEndpoint);  
        CatalogEndpoint = string.Format("{0}:5101", baseEndpoint);  
        OrdersEndpoint = string.Format("{0}:5102", baseEndpoint);  
        BasketEndpoint = string.Format("{0}:5103", baseEndpoint);  
        IdentityEndpoint = string.Format("{0}:5105/connect/authorize", baseEndpoint);  
        UserInfoEndpoint = string.Format("{0}:5105/connect/userinfo", baseEndpoint);  
        TokenEndpoint = string.Format("{0}:5105/connect/token", baseEndpoint);  
        LogoutEndpoint = string.Format("{0}:5105/connect/endsession", baseEndpoint);  
        IdentityCallback = string.Format("{0}:5105/xamarincallback", baseEndpoint);  
        LogoutCallback = string.Format("{0}:5105/Account/Redirecting", baseEndpoint);  
    }  
}

Each time the BaseEndpoint property is set, the UpdateEndpoint method is called. This method updates a series of properties, all of which are based on the UrlBase user setting that's provided by the Settings class that represent different endpoints that the eShopOnContainers mobile app connects to.

Data Binding to User Settings

In the eShopOnContainers mobile app, the SettingsView exposes two user settings. These settings allow configuration of whether the app should retrieve data from microservices that are deployed as Docker containers, or whether the app should retrieve data from mock services that don't require an internet connection. When choosing to retrieve data from containerized microservices, a base endpoint URL for the microservices must be specified. Figure 7-1 shows the SettingsView when the user has chosen to retrieve data from containerized microservices.

User settings exposed by the eShopOnContainers mobile app

Figure 7-1: User settings exposed by the eShopOnContainers mobile app

Data binding can be used to retrieve and set settings exposed by the Settings class. This is achieved by controls on the view binding to view model properties that in turn access properties in the Settings class, and raising a property changed notification if the settings value has changed. For information about how the eShopOnContainers mobile app constructs view models and associates them to views, see Automatically Creating a View Model with a View Model Locator.

The following code example shows the Entry control from the SettingsView that allows the user to enter a base endpoint URL for the containerized microservices:

<Entry Text="{Binding Endpoint, Mode=TwoWay}" />

This Entry control binds to the Endpoint property of the SettingsViewModel class, using a two-way binding. The following code example shows the Endpoint property:

public string Endpoint  
{  
    get { return _endpoint; }  
    set  
    {  
        _endpoint = value;  

        if(!string.IsNullOrEmpty(_endpoint))  
        {  
            UpdateEndpoint(_endpoint);  
        }  

        RaisePropertyChanged(() => Endpoint);  
    }  
}

When the Endpoint property is set the UpdateEndpoint method is called, provided that the supplied value is valid, and property changed notification is raised. The following code example shows the UpdateEndpoint method:

private void UpdateEndpoint(string endpoint)  
{  
    Settings.UrlBase = endpoint;  
}

This method updates the UrlBase property in the Settings class with the base endpoint URL value entered by the user, which causes it to be persisted to platform-specific storage.

When the SettingsView is navigated to, the InitializeAsync method in the SettingsViewModel class is executed. The following code example shows this method:

public override Task InitializeAsync(object navigationData)  
{  
    ...  
    Endpoint = Settings.UrlBase;  
    ...  
}

The method sets the Endpoint property to the value of the UrlBase property in the Settings class. Accessing the UrlBase property causes the Xam.Plugins.Settings library to retrieve the settings value from platform-specific storage. For information about how the InitializeAsync method is invoked, see Passing Parameters During Navigation.

This mechanism ensures that whenever a user navigates to the SettingsView, user settings are retrieved from platform-specific storage and presented through data binding. Then, if the user changes the settings values, data binding ensures that they are immediately persisted back to platform-specific storage.

Summary

Settings allow the separation of data that configures the behavior of an app from the code, allowing the behavior to be changed without rebuilding the app. App settings are data that an app creates and manages, and user settings are the customizable settings of an app that affect the behavior of the app and don't require frequent re-adjustment.

The Xam.Plugins.Settings library provides a consistent, type-safe, cross-platform approach for persisting and retrieving app and user settings, and data binding can be used to access settings created with the library.