Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I abstract Microsoft.Maui.Storage.Preferences as IPreferences in MAUI

I'm writing a .NET MAUI app and I would like to use Microsoft.Maui.Storage.Preferences in my ViewModel, however would prefer not to tie my ViewModel to the static Preferences class otherwise it will be hard to test. So I noticed there is an IPreferences interface, but I don't know what it's purpose is, as I can't inject a static implementation (and Preferences is static).

In my startup class I do the usual builder.Services.AddSingleton() and .AddTransient():

builder.Services
        .AddSingleton<AppShell>()
        .AddTransient<MyViewModel>()
        ...

But I can't do this with a static class. This won't work because you can't use a static class as a type argument:

        .AddSingleton<IPreferences, Preferences>()

This doesn't work because it's not provided by the framework:

        .AddSingleton<IPreferences>()

And I tried to get fancy:

        .AddSingleton<IPreferences>(_ => Preferences.Default)

but I get this error when using it:

    _preferences.Get("SomeKey", DateTime.Now); // error here, but _preferences is defined

[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object.
[mono-rt]    at Microsoft.Maui.Storage.PreferencesImplementation.Get[DateTime](String key, DateTime defaultValue, String sharedName) in D:\a\_work\1\s\src\Essentials\src\Preferences\Preferences.android.cs:line 141
[mono-rt]    at ... my filenames removed ... in ...\Shells\AppShell.xaml.cs:line 51
[mono-rt]    at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
[mono-rt]    at Android.App.SyncContext.<>c__DisplayClass2_0.<Post>b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:line 36
[mono-rt]    at Java.Lang.Thread.RunnableImplementor.Run() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:line 36
[mono-rt]    at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Java.Lang.IRunnable.cs:line 84
[mono-rt]    at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 22

Can I inject IPreferences or do I have to create my own interface backed by the static Preferences?

like image 977
thinkOfaNumber Avatar asked Oct 15 '25 05:10

thinkOfaNumber


1 Answers

IPreferences is for saving small key-value pairs. You can inject it referencing Preferences.Default.

And then use:

settings.Get("Language", 0);

Where settings is:

IPreferences settings;

What I like to do is make SettingsService, and then use:

public int Language
{
    get => settings.Get("Language", 0);
    set => settings.Set("Language", value);
}

There are other ways to handle your settings, but for few values, this works for me.

Edit(The code you requested.)

Injecting:

builder.Services.AddSingleton<ISettings>(new SettingsService(Preferences.Default));

ISettings interface:

public interface ISettings
{
    int Language { get; set; }
}

SettingsService class:

internal class SettingsService : ISettings
{
    IPreferences settings;

    public SettingsService(IPreferences settings)
    {
        this.settings = settings;
    }

    public int Language
    {
        get => settings.Get("Language", 0);
        set => settings.Set("Language", value);
    }
}

Using in ViewModel:

public MyViewModel(ISettings settings)
{
    lang = settings.Language;
}

Edit2: since you do not want to "manually construct". You can do this.

builder.Services.AddSingleton<IPreferences>(Preferences.Default);
builder.Services.AddSingleton<ISettings, SettingsService>();

With this you can use IPreferences, as well as ISettings. And SettingsService constructor will use the IPreferences injected here.

like image 66
H.A.H. Avatar answered Oct 17 '25 21:10

H.A.H.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!