![]() |
VOOZH | about |
dotnet add package Shiny.Extensions.Serialization --version 5.1.0
NuGet\Install-Package Shiny.Extensions.Serialization -Version 5.1.0
<PackageReference Include="Shiny.Extensions.Serialization" Version="5.1.0" />
<PackageVersion Include="Shiny.Extensions.Serialization" Version="5.1.0" />Directory.Packages.props
<PackageReference Include="Shiny.Extensions.Serialization" />Project file
paket add Shiny.Extensions.Serialization --version 5.1.0
#r "nuget: Shiny.Extensions.Serialization, 5.1.0"
#:package Shiny.Extensions.Serialization@5.1.0
#addin nuget:?package=Shiny.Extensions.Serialization&version=5.1.0Install as a Cake Addin
#tool nuget:?package=Shiny.Extensions.Serialization&version=5.1.0Install as a Cake Tool
OnResolved compose naturallyActivatorUtilities-style constructor selection ([ActivatorUtilitiesConstructor] and [FromKeyedServices] honored)GetService (no throw when unregistered) with fallback to the declared default valueOnResolved<T>(hook) chain extension for one-shot post-construction hooksTHIS:
using Microsoft.Extensions.DependencyInjection;
using Shiny;
// given the following code from a user
namespace Sample
{
public interface IStandardInterface;
public interface IStandardInterface2;
[Service(ServiceLifetime.Singleton)]
public class ImplementationOnly;
[Service(ServiceLifetime.Transient, "ImplOnly")]
public class KeyedImplementationOnly;
[Service(ServiceLifetime.Singleton)]
public class StandardImplementation : IStandardInterface;
[Service(ServiceLifetime.Scoped, "Standard")]
public class KeyedStandardImplementation : IStandardInterface;
[Service(ServiceLifetime.Singleton)]
public class MultipleImplementation : IStandardInterface, IStandardInterface2;
[Service(ServiceLifetime.Scoped)]
public class ScopedMultipleImplementation : IStandardInterface, IStandardInterface2;
[Service(ServiceLifetime.Scoped, "KeyedGeneric")]
public class TestGeneric<T1, T2>
{
public T1 Value1 { get; set; }
public T2 Value2 { get; set; }
}
}
GENERATES THIS:
// <auto-generated />
using global::Microsoft.Extensions.DependencyInjection;
using global::Shiny;
namespace Sample
{
public static class __GeneratedRegistrations
{
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection AddGeneratedServices(
this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services
)
{
services.AddSingleton<global::Sample.ImplementationOnly>();
services.AddKeyedTransient<global::Sample.KeyedImplementationOnly>("ImplOnly");
services.AddSingleton<global::Sample.IStandardInterface, global::Sample.StandardImplementation>();
services.AddKeyedScoped<global::Sample.IStandardInterface, global::Sample.KeyedStandardImplementation>("Standard");
services.AddSingletonAsImplementedInterfaces<global::Sample.MultipleImplementation>();
services.AddScopedAsImplementedInterfaces<global::Sample.ScopedMultipleImplementation>();
services.AddKeyedScoped(typeof(global::Sample.TestGeneric<,>), "KeyedGeneric");
return services;
}
}
}
Shiny.Extensions.DependencyInjection// during your app startup - use your service collection
builder.Services.AddGeneratedServices();
[Service(ServiceLifetime.Singleton, "optional key")] attribute to your classes and specify the lifetime and optional keyISerializer backed by source-generated JsonSerializerContexts, no reflection, AOT-cleanShiny.Json static accessor — self-bootstrapping, sibling to Shiny.Stores for mobile cold-start[ShinyJsonContext] on any user-declared JsonSerializerContext partial → source generator emits a [ModuleInitializer] that auto-registers it. No services.AddJsonContext(...) boilerplate needed[ShinyJsonInclude] on a type (or [assembly: ShinyJsonInclude(typeof(T))]) → AOT-safe collection wrappers for List<T>, T[], IEnumerable<T>, IReadOnlyList<T>, IList<T>, ICollection<T>, IAsyncEnumerable<T> — solves the "inline [JsonConverter] works but List<T> fails" trapTypeInfoResolverChain. Element types from one context compose with collection wrappers from anotherservices.AddJsonSerialization() / AddJsonContext(...) / ConfigureJsonSerializer(...) for DI-side wiring; Shiny.Json.CreateTestScope() for test isolationShiny.Extensions.Serialization[Shiny.ShinyJsonContext]:
using System.Text.Json.Serialization;
using Shiny;
[ShinyJsonContext]
[JsonSerializable(typeof(MyDto))]
[JsonSerializable(typeof(MyOtherDto))]
internal partial class MyAppJsonContext : JsonSerializerContext;
[ModuleInitializer] calling Shiny.Json.AddContext(MyAppJsonContext.Default) before Main, so both DI consumers and the static Shiny.Json.Default accessor see your types — no services.AddJsonContext(...) call needed.[ShinyJsonInclude]:
[ShinyJsonInclude]
public partial class MyDto { /* ... */ }
List<MyDto>, MyDto[], IEnumerable<MyDto> and friends now serialize AOT-safely.// Static access — works before DI exists (useful for mobile cold-start through Shiny.Stores)
var json = Shiny.Json.Default.Serialize(new MyDto { Name = "Allan" });
// DI access — same shared instance
public class MyService(ISerializer serializer) { /* ... */ }
[Bind] attribute on partial properties - emits getter/setter bodies that round-trip through the store (no INPC required, no runtime reflection, fully AOT)Shiny.Stores.Default/Secure/Keyed(...) accessor for direct ad-hoc reads/writesIKeyValueStore to plug in your own storeShiny.Extensions.StoresShiny.Stores accessor self-bootstraps on first use:
builder.Services.AddShinyStores();
var host = builder.Build();
On Blazor WebAssembly (where LocalStorageKeyValueStore needs IJSRuntime), also call host.Services.UseShinyStores() after Build() to snapshot the DI-resolved store into the static accessor.partial class with [Bind] partial properties:
using Shiny;
[Singleton]
public partial class AppSettings
{
[Bind] // default store
public partial string Theme { get; set; }
[Bind("secure")] // secure store
public partial string Token { get; set; }
}
AppSettings anywhere. Set properties — they persist. Read properties — they come from the store.Or skip the class and use the static accessor:
Shiny.Stores.Default.Set("theme", "dark");
var theme = Shiny.Stores.Default.Get<string>("theme");
| Platform | Key | Description |
|---|---|---|
| Android | StoreKeys.Default |
Preferences |
| Android | StoreKeys.Secure |
Secure Storage |
| iOS | StoreKeys.Default |
NSUserDefaults |
| iOS | StoreKeys.Secure |
Keychain |
| Windows | StoreKeys.Default |
ApplicationData.LocalSettings |
| Windows | StoreKeys.Secure |
Secure Storage |
| WebAssembly | StoreKeys.Default |
localStorage |
| WebAssembly | "session" |
sessionStorage |
| All | any | In-memory dictionary (great for testing) |
For WebAssembly, install the Shiny.Extensions.Stores.Web package and add services.AddShinyWebAssemblyStores() to your service collection.
IWebModuleShiny.Extensions.WebHostingIWebModule:
using Shiny;
public class MyWebModule : IWebModule
{
public void Add(WebApplicationBuilder builder)
{
// Register your services here
}
public void Use(WebApplication app)
{
// Configure your middleware/endpoints here
}
}
using Shiny;
var builder = WebApplication.CreateBuilder(args);
builder.AddInfrastructureModules(new MyWebModule());
var app = builder.Build();
app.UseInfrastructureModules();
IMauiModuleHost.Services for accessing the service provider anywhereIAppSupport — device info (manufacturer, model, platform, idiom, OS version), browser/map launch, programmatic orientation lock, and live change events for orientation, culture, and time zone (native listeners on iOS/Android/Windows, polling fallback elsewhere)IAppStore — cross-platform store version lookups + deep links for Apple App Store (iTunes Search API), Google Play (HTML scrape), and Microsoft Store (DisplayCatalog API)Shiny.Extensions.MauiHostingIMauiModule:
using Shiny;
public class MyMauiModule : IMauiModule
{
public void Add(MauiAppBuilder builder)
{
// Register your services here
}
public void Use(IPlatformApplication app)
{
// Post-build initialization here (do NOT block)
}
}
MauiProgram.cs:
using Shiny;
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.AddInfrastructureModules(new MyMauiModule()) // your IMauiModule list
.AddAppSupport() // IAppSupport
.AddAppStore(opts => // optional: IAppStore + config
{
opts.AppleAppId = "1234567890";
opts.WindowsProductId = "9NBLGGH4NNS1";
});
return builder.Build();
Host.Servicespublic class MyVm(IAppSupport app)
{
void Hook()
{
// Snapshot
var version = app.AppVersion;
var platform = app.Platform; // "Android", "iOS", "WinUI", "macOS"
var idiom = app.DeviceIdiom; // Phone, Tablet, Desktop, …
var orientation = app.CurrentOrientation;
var culture = app.CurrentCulture;
// Live updates
app.OrientationChanged += (s, e) => { /* new DisplayOrientation */ };
app.CultureChanged += (s, e) => { /* new CultureInfo */ };
app.TimeZoneChanged += (s, e) => { /* new TimeZoneInfo */ };
// Programmatic orientation lock
_ = app.SetOrientation(DisplayOrientation.Landscape);
_ = app.ResetOrientation();
}
}
public class UpdateChecker(IAppStore store)
{
public async Task Check()
{
var result = await store.GetCurrent();
if (result?.NeedsUpdate == true)
await store.OpenStore();
}
public Task Review() => store.OpenReviewPage();
}
IAppSupport for Blazor WebAssembly — app version, browser user-agent (raw string + best-effort parsed browser Version), screen and viewport dimensions, plus live culture / time-zone change eventsIJSInProcessRuntime (same approach as Shiny.Extensions.Stores.Web)Shiny.Extensions.BlazorHostingwwwroot/index.html before blazor.webassembly.js:
<script src="_content/Shiny.Extensions.BlazorHosting/shiny-appsupport.js"></script>
ThisAssembly):
using Shiny;
builder.Services.AddAppSupport(ThisAssembly.AssemblyVersion);
IAppSupport anywhere:
public class MyComponent(IAppSupport app)
{
void Hook()
{
// Snapshot
var version = app.AppVersion;
var ua = app.UserAgent;
var browser = app.UserAgentVersion;
var (w, h) = (app.BrowserWidth, app.BrowserHeight); // viewport — read live
var (sw, sh) = (app.ScreenWidth, app.ScreenHeight); // physical screen
// Live updates
app.CultureChanged += (s, e) => { /* new CultureInfo */ };
app.TimeZoneChanged += (s, e) => { /* new TimeZoneInfo */ };
}
}
| Package | Description |
|---|---|
Shiny.Extensions.DependencyInjection |
Attribute-driven DI registration with source generators |
Shiny.Extensions.Serialization |
Centralized AOT-safe JSON serializer + [ShinyJsonContext]/[ShinyJsonInclude] source generator |
Shiny.Extensions.Stores |
Cross-platform key/value store abstraction |
Shiny.Extensions.Stores.Web |
Blazor WebAssembly localStorage/sessionStorage |
Shiny.Extensions.WebHosting |
ASP.NET modular web hosting with IWebModule |
Shiny.Extensions.MauiHosting |
MAUI modular hosting with IMauiModule and platform lifecycle hooks |
Shiny.Extensions.BlazorHosting |
Blazor WebAssembly IAppSupport — browser/device info and culture/time-zone change events |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 5 NuGet packages that depend on Shiny.Extensions.Serialization:
| Package | Downloads |
|---|---|
|
Shiny.Core
The Shiny Core Foundation where all Shiny modules are built on |
|
|
Shiny.Notifications
Shiny addon for all your notification needs |
|
|
Shiny.Push
Shiny addon for all your push notification needs |
|
|
Shiny.BluetoothLE.Common
Shiny BluetoothLE - Common components for Hosting and Client |
|
|
Shiny.BluetoothLE
Shiny Reactive BluetoothLE Plugin for client/central operations |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.1.0 | 214 | 6/14/2026 |
| 5.1.0-beta-0054 | 102 | 6/14/2026 |
| 5.1.0-beta-0052 | 116 | 6/12/2026 |
| 5.1.0-beta-0051 | 113 | 6/12/2026 |
| 5.0.0 | 337 | 6/8/2026 |
| 5.0.0-beta-0052 | 432 | 6/7/2026 |
| 5.0.0-beta-0051 | 1,522 | 6/7/2026 |