-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Essentials static Default properties need a public registration mechanism - Every Essentials API (Preferences, FilePicker, SecureStorage, etc.) is inaccessible to custom backends without reflection hacks #34100
Description
Third-party platform backends (e.g. Linux/GTK) cannot wire their Essentials implementations into the static Default properties (FilePicker.Default, Preferences.Default, SecureStorage.Default, etc.) without using private reflection. The internal SetDefault() method should be made public or an official DI-based registration path should be provided.
Problem
When building a custom MAUI platform backend, registering services into DI (e.g. builder.Services.AddSingleton<IPreferences, LinuxPreferences>()) is not sufficient — the static XXX.Default properties still resolve to the reference assembly stubs, which throw NotImplementedInReferenceAssemblyException at runtime.
The only way to wire custom implementations today is via reflection:
// Current workaround — fragile and unsupported
var setDefault = typeof(Preferences).GetMethod("SetDefault",
BindingFlags.Static | BindingFlags.NonPublic);
setDefault?.Invoke(null, new object[] { new LinuxPreferences() });This is needed for every Essentials API surface:
Preferences.DefaultFilePicker.DefaultSecureStorage.DefaultClipboard.DefaultMediaPicker.DefaultLauncher.Default- etc.
Impact
Any code that uses the static XXX.Default pattern (which is very common in MAUI apps and docs) immediately throws on custom backends, even though a working implementation exists and is registered in DI.
Real-world example
// App.cs — crashes on Linux/GTK with NotImplementedInReferenceAssemblyException
var savedWidth = Preferences.Default.Get("window_width", 1280.0);We had to guard this with #if LINUXGTK conditionals throughout the app, which defeats the purpose of cross-platform code.
Proposed Solution
Option A (minimal): Make SetDefault() public on all Essentials types so third-party backends can call it during host building:
// In AddLinuxGtk4Essentials():
Preferences.SetDefault(new LinuxPreferences());
FilePicker.SetDefault(new LinuxFilePicker());Option B (preferred): Provide an official IServiceCollection extension that auto-wires both DI and the static defaults:
builder.Services.AddEssentialsImplementation<IPreferences, LinuxPreferences>();
// This would: (1) register in DI, and (2) set the static DefaultOption C: Resolve Default from the DI container at first access instead of using a compile-time static field, so DI registration alone is sufficient.
Affected APIs
All types under Microsoft.Maui.Storage, Microsoft.Maui.ApplicationModel, Microsoft.Maui.Devices, Microsoft.Maui.Media, etc. that expose a static Default property backed by an internal SetDefault() method.
Environment
- .NET 10 Preview
- Custom platform backend: Linux/GTK via
Platform.Maui.Linux.Gtk4 - MAUI Essentials reference assemblies