AppSettingsMaui 1.0.0-preview2

This is a prerelease version of AppSettingsMaui.
dotnet add package AppSettingsMaui --version 1.0.0-preview2
                    
NuGet\Install-Package AppSettingsMaui -Version 1.0.0-preview2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="AppSettingsMaui" Version="1.0.0-preview2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AppSettingsMaui" Version="1.0.0-preview2" />
                    
Directory.Packages.props
<PackageReference Include="AppSettingsMaui" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add AppSettingsMaui --version 1.0.0-preview2
                    
#r "nuget: AppSettingsMaui, 1.0.0-preview2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package AppSettingsMaui@1.0.0-preview2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=AppSettingsMaui&version=1.0.0-preview2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=AppSettingsMaui&version=1.0.0-preview2&prerelease
                    
Install as a Cake Tool

MauiSettings

A nuget to improve settings storage (locally and eventually in the cloud) on .NET MAUI projects.

The plugin idea is based on the Advexp.Settings.Local nuget by Alexey Ivakin</br> Repo: https://bitbucket.org/advexp/component-advexp.settings/src/master/</br> License: Apache-2.0 (https://licenses.nuget.org/Apache-2.0)</br>

This project was created from scratch, however uses the basic idea to keep all Settings in the static object. All taken and changed files have been marked so.

Support me

If you want to support me, you can order over following affilate links (I'll get a small share from your purchase from the corresponding store).

(*) Affiliate link Thank you very much for supporting me!

Nuget

Get the latest version from nuget.org<br> NuGet NuGet

Usage

JsonSerializerContext

See the ExampleApp project for an example of how to create a JsonSerializerContext and pass it to the LoadSettings and SaveSettings methods. Add each object, which needs to be serialized/deserialized as JsonSerializable attribute.

    [JsonSerializable(typeof(Version))]
    [JsonSerializable(typeof(SettingsItem))]
    [JsonSourceGenerationOptions(WriteIndented = true)]
    public partial class AppSourceGenerationContext : JsonSerializerContext { }

Very important: Add each type which is used for your SettingsApp class here!

You also can set the Context globally by setting the property in the AppHostBuilderExtensions.cs file of your app:

    public static MauiAppBuilder ConfigureSettings(this MauiAppBuilder builder, string? hash = null, IDispatcher? dispatcher = null)
    {
        dispatcher ??= builder.Services.BuildServiceProvider().GetService<IDispatcher>();
        AppSettingsService settings = new()
        {
            Dispatcher = dispatcher,
            PassPhrase = hash,
            Context = AppSourceGenerationContext.Default
        };
        builder.Services.TryAddSingleton<IAppSettingsService>(settings);
        return builder;
    }

Settings Object

In the .NET MAUI project, create a new Class in the Services folder (for instance AppSettingsService.cs) holding your setting properties. Don't forget to also create an Interface for the service (for instance IAppSettingsService.cs) and add the properties there as well, so you can inject the service in your ViewModels and App.xaml.cs file.

public partial class AppSettingsService : MauiAppSettings<AppSettingsService>, IAppSettingsService
{
    
    #region Settings

    #region Version
    [ObservableProperty, MauiAppSetting(Name = nameof(App_SettingsVersion))]
    public partial Version App_SettingsVersion { get; set; } = new("1.0.0");

    #endregion

    #region CloudSync
    [ObservableProperty, MauiAppSetting(Name = nameof(Cloud_ShowInitialPrompt), DefaultValue = true)]
    public partial bool Cloud_ShowInitialPrompt { get; set; }

    [ObservableProperty, MauiAppSetting(Name = nameof(Cloud_ShowInitialPrompt), DefaultValue = SettingsStaticDefault.Cloud_EnableSync)]
    public partial bool Cloud_EnableSync { get; set; }
    #endregion

    #region Theme 
    [ObservableProperty, MauiAppSetting(Name = nameof(Theme_UseDeviceDefaultSettings), DefaultValue = SettingsStaticDefault.General_UseDeviceSettings)]
    public partial bool Theme_UseDeviceDefaultSettings { get; set; }

    [ObservableProperty, MauiAppSetting(Name = nameof(Theme_UseDarkTheme), DefaultValue = SettingsStaticDefault.General_UseDarkTheme)]
    public partial bool Theme_UseDarkTheme { get; set; }

    [ObservableProperty, MauiAppSetting(Name = nameof(Theme_PrimaryThemeColor), DefaultValue = SettingsStaticDefault.Theme_PrimaryThemeColor)]
    public partial string Theme_PrimaryThemeColor { get; set; }

    #endregion

    #region Localization

    [ObservableProperty, MauiAppSetting(Name = nameof(Localization_CultureCode), DefaultValue = SettingsStaticDefault.Localization_Default)]
    public partial string Localization_CultureCode { get; set; }

    #endregion

    #region Secure

    // Encrypt: The value is encrypt before saving it on the device, and decrypt when loaded
    // Note: Only `Secure` properties can be encrypted
    [ObservableProperty, MauiAppSetting(Name = nameof(Localization_CultureCode), DefaultValue ="", Secure = true, Encrypt = true)]
    public partial string User_Username { get; set; }

    // SkipForExport: Value is not added to the Dictionary when exporting the settings
    [ObservableProperty, MauiAppSetting(Name = nameof(Localization_CultureCode), DefaultValue ="", Secure = true, Encrypt = true, SkipForExport = true)]
    public partial string User_Password { get; set; }

    #endregion

    #endregion
}

Dependency Injection

You can then inject the IAppSettingsService on each ViewModel or the App.xaml.cs, where needed.

    readonly IAppSettingsService? appSettings;
    public App(IServiceProvider serviceProvider, IAppSettingsService appSettings)
    {
        this.serviceProvider = serviceProvider;
        this.appSettings = appSettings;
        InitializeComponent();
    }

Load

To load the settings from the storage, call SettingsApp.LoadSettings() (mostly in the App constructor of your App.xmls file. The project uses the Maui.Storage.Preferences in order to store the settings on the corresponding device.

// Load settings with the app context and a shared name (optional) ...
appSettings!.LoadSettings(AppSourceGenerationContext.Default, SharedName);

Save

Whenever you do make changes to a settings property of your class, call SettingsApp.SaveSettings(). This will write the settings to the storage.

        [ObservableProperty]
        public partial bool AutoSyncOnStartup { get; set; } = true;
        partial void OnAutoSyncOnStartupChanged(bool value)
        {
            if (!IsLoading)
            {
                appSettings!.SevDesk_AutoSyncOnStartup = value;
                appSettings!.SaveSetting(setting => appSettings.SevDesk_AutoSyncOnStartup);
            }
        }

If you want to save a secure or/and encrypted property, you have to provide a key for encryption/decryption and use the async method:

        [ObservableProperty]
        public partial string AccessToken { get; set; } = string.Empty;
        partial void OnAccessTokenChanged(string value)
        {
            AccessTokenValid = !string.IsNullOrEmpty(value);
            if (!IsLoading && AccessTokenValid && value is not null)
            {
                appSettings!.SevDesk_AccessToken = value;
                appSettings!.SaveSettingAsync(
                    setting => appSettings.SevDesk_AccessToken,
                    appSettings.TryDecryptPassphrase(appSettings.Firebase_PassPhrase, appSettings.Encryption_Password)
                    );
            }
        }

Encryption

With the service, you also can encrypt secure properties with a AES encryption. An example how it works is shown below. Sample: https://github.com/AndreasReitberger/MauiSettings/tree/main/src/MauiSettings.Example

App.xaml.cs

An example of how to load the settings from the App.xaml.

public partial class App : Application
{
    // Example key, it is recommended to generate the key on the device and save it as `Secure` property instead of
    // adding it in clear text to the source code.
    public static string Hash = "mYGUbR61NUNjIvdEv/veySPxQEWcCRUZ3SZ7TT72IuI=";
    
    readonly IAppSettingsService? appSettings;
    public App(IAppSettingsService appSettings)
    {
        this.appSettings = appSettings;
        InitializeComponent();

        // Example of how to generate a new key
        //string t = EncryptionManager.GenerateBase64Key();

        // Only Async methods do support encryption!
        _ = Task.Run(async () => await appSettings.LoadSettingsAsync(Hash));
        MainPage = new AppShell();
    }

    protected override void OnSleep()
    {
        base.OnSleep();
        if (appSettings?.SettingsChanged is true)
        {
            try
            {
                appSettings.SaveSettings(Hash);
            }
            catch (Exception)
            {

            }
        }
    }
}

MainPageViewModel

An example of aViewModel loading and saving encrypted settings.

public partial class MainPageViewModel : ObservableObject
{
    #region Fields
    readonly IAppSettingsService? appSettings;
    #endregion

    #region Settings
    [ObservableProperty]
    bool isLoading = false;

    [ObservableProperty]
    string hashKey = App.Hash;

    [ObservableProperty]
    string licenseInfo = string.Empty;
    partial void OnLicenseInfoChanged(string value)
    {
        if (!IsLoading)
        {
            appSettings!.LicenseInfo = value;
            appSettings!.SaveSetting(setting => appSettings.LicenseInfo);
        }
    }

    [ObservableProperty]
    ObservableCollection<SettingsItem> settings = [];
    #endregion

    #region Ctor
    public MainPageViewModel(IAppSettingsService appSettings)
    {
        this.appSettings = appSettings;
        LoadSettings();
    }
    #endregion

    #region Methods
    void LoadSettings()
    {
        IsLoading = true;

        LicenseInfo = appSettings!.LicenseInfo;

        IsLoading = false;
    }
    #endregion

    #region Commands
    [RelayCommand]
    async Task SaveSettings() => await appSettings!.SaveSettingsAsync(key: App.Hash);

    [RelayCommand]
    async Task LoadSettingsFromDevice()
    {
        try
        {
            await appSettings!.LoadSettingsAsync(key: App.Hash);
            LoadSettings();
        }
        catch(Exception)
        {
            // Throus if the key missmatches
        }
    }

    [RelayCommand]
    async Task ExchangeHashKey()
    {
        string newKey = EncryptionManager.GenerateBase64Key();
        await appSettings!.ExhangeKeyAsync(oldKey: App.Hash, newKey: newKey);
        App.Hash = HashKey = newKey;
        LoadSettings();
    }

    [RelayCommand]
    async Task ToDictionary()
    {
        // All "SkipForExport" should be missing here.
        Dictionary<string, Tuple<object?, Type>> dict = await appSettings.ToDictionaryAsync();
        Settings = [.. dict.Select(kp => new SettingsItem() { Key = kp.Key, Value = kp.Value.Item1.ToString() })];
    }
    #endregion
}

For more information, please see the example project.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-android36.0 is compatible.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-ios26.0 is compatible.  net10.0-maccatalyst was computed.  net10.0-maccatalyst26.0 is compatible.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net10.0-windows10.0.19041 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-preview2 593 6/3/2026
1.0.0-preview1 140 5/27/2026

Check GitHub releases for changelog.