Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More
Stores Release Notes
4.1 - May 29, 2026
Section titled “4.1 - May 29, 2026” Fix
StoreExtensions.Get<T>(store, key, defaultValue) now checks Contains(key) before reading, so a stored 0, false, or default-enum value is no longer mistaken for a missing key and replaced with the supplied default4.0 - May 27, 2026
Section titled “4.0 - May 27, 2026” Enhancement
Shiny.Stores.Default and Shiny.Stores.Secure are now self-bootstrapping. On mobile/desktop they lazily construct the platform-native store on first access — no post-build UseShinyStores() call is required. Generated [Bind] property accessors will work even if read during host construction (fixes InvalidOperationException: Shiny stores not initialized for code paths that touch settings before the post-build init ran) Feature
New
Shiny.Stores.Register(object key, IKeyValueStore store) — registers or overrides a store for any key. Use for tests, custom store keys referenced by [Bind("custom-key")], or scenarios where the store can’t be constructed statically (Blazor IJSRuntime-backed stores) Feature
New
Shiny.Stores.Serializer — single shared DefaultSerializer instance used by both the static accessor and DI. services.AddJsonContext(...) now installs its context onto this same instance, so static and DI consumers can’t drift Feature
New
Shiny.Stores.Reset() — clears all static registrations and forces re-bootstrap on next access (useful for test isolation) Enhancement
UseShinyStores() is now optional on mobile/desktop. It remains useful for Blazor (where LocalStorageKeyValueStore needs IJSRuntime from the built provider) and for snapshotting keyed IKeyValueStore registrations from DI into the static accessor BREAKING Enhancement
IKeyValueStore has been reshaped to a generic, AOT-friendly API. The Alias property is gone; object? Get(Type, string) and Set(string, object) have been replaced by T? Get<T>(string) and Set<T>(string, T) BREAKING Enhancement
ISerializer is now generic-first (T Deserialize<T> / string Serialize<T>). Runtime-typed overloads object? Deserialize(Type, string) and string Serialize(object, Type?) remain for the object binder BREAKING Enhancement
DefaultSerializer is now AOT-clean and strict — types must be supplied via a JsonSerializerContext. Register one with services.AddJsonContext(MyJsonContext.Default). There is no longer a reflection-based fallback by default; for non-AOT scenarios (e.g. unit tests) add serializer.Options.TypeInfoResolverChain.Add(new DefaultJsonTypeInfoResolver()) explicitly Feature
New
StoreKeys constants (StoreKeys.Default = "settings", StoreKeys.Secure = "secure") — stores are now registered as keyed singletons in DI instead of by Alias. Resolve with sp.GetRequiredKeyedService<IKeyValueStore>(StoreKeys.Default) BREAKING Enhancement
IKeyValueStoreFactory and KeyValueStoreFactory have been removed. Use keyed DI lookups against StoreKeys (or your own keys) instead of factory.GetStore(alias) BREAKING Enhancement
IObjectStoreBinder.Bind now takes object? storeKey (a DI service key) instead of string? keyValueStoreAlias. The implementation now depends on IServiceProvider + ISerializer, not IKeyValueStoreFactory BREAKING Enhancement
ObjectStoreBinderAttribute.StoreAlias has been renamed to StoreKey BREAKING Enhancement
AddPersistentService<TImpl>(string? alias) is now AddPersistentService<TImpl>(Func<IServiceProvider, TImpl> factory, object? storeKey = null). A factory is required to keep registration AOT-clean. The non-generic AddPersistentService(Type, ...) overload has been removed Feature
New static
Shiny.Stores accessor — Stores.Default, Stores.Secure, and Stores.Keyed(key) resolve the registered IKeyValueStore for the corresponding service key. Initialize once after the service provider is built by calling serviceProvider.UseShinyStores() (or the lower-level Stores.Initialize(serviceProvider)) Feature
Object binding is now source-generated via the new
[Bind] attribute (in Shiny.Extensions.DependencyInjection). The DI source generator emits partial property bodies that call Stores.Default.Set/Get (or Stores.Secure, Stores.Keyed(...)). No INotifyPropertyChanged required, no runtime reflection, fully AOT-clean BREAKING Enhancement
Removed
IObjectStoreBinder / ObjectStoreBinder, ObjectStoreBinderAttribute, BindOnResolve(), and AddPersistentService<T>(). The runtime INPC-based binder has been replaced by source-generated [Bind] properties — migrate by marking your settings class partial, declaring [Bind] partial properties, and (optionally) marking the class [Singleton] for auto-registration Feature
New
services.AddJsonContext(JsonSerializerContext) extension — installs (or chains to) the shared DefaultSerializer and registers types for AOT-safe serialization Feature
Repositories have been folded into
Shiny.Extensions.Stores. New IRepository + IRepositoryEntity API with the FileSystemRepository implementation (transactional, in-memory-cached, {EntityName}_{Id}.shiny files), RepositoryAction change-event enum, RepositoryException, and services.AddDefaultRepository(DirectoryInfo? rootDir = null) registration helper Feature Blazor WebAssembly
New
LocalStorageRepository — mirrors FileSystemRepository over the browser’s localStorage via shiny:repo:{EntityName}: prefixed keys. Register with services.AddLocalStorageRepository() BREAKING Enhancement Blazor WebAssembly
LocalStorageKeyValueStore has been rewritten to use ISerializer and prefix-namespaced keys (shiny:kvs:settings:). Register with services.AddLocalStorageKeyValueStore() — registers under StoreKeys.Default and exposes the unkeyed default BREAKING Enhancement Blazor WebAssembly
BaseKeyValueStore and SessionStorageKeyValueStore have been removed. The Web package now requires the _content/Shiny.Extensions.Stores.Web/shiny-storage.js script to be loaded in index.html before blazor.webassembly.js BREAKING Enhancement
FileKeyValueStore has been removed — use the new IRepository API for entity-style persistence Fix Android
SecureKeyValueStore is now functional — its constructor was previously commented out and the class could not be instantiated Fix Windows
SecureKeyValueStore had a syntactically broken constructor; the class is now functional2.0 - March 9, 2026
Section titled “2.0 - March 9, 2026” Enhancement
Updated to align with Shiny Extensions 2.0 — no API changes
1.2.2 - July 26, 2025
Section titled “1.2.2 - July 26, 2025” Fix
Booleans with false were not binding properly on stores
Fix iOS
Secure storage would not correctly store or clear all values
1.0 - July 3, 2025
Section titled “1.0 - July 3, 2025” Feature
Initial Public Release