Shiny.Extensions.DependencyInjection
4.0.0
Prefix Reserved
dotnet add package Shiny.Extensions.DependencyInjection --version 4.0.0
NuGet\Install-Package Shiny.Extensions.DependencyInjection -Version 4.0.0
<PackageReference Include="Shiny.Extensions.DependencyInjection" Version="4.0.0" />
<PackageVersion Include="Shiny.Extensions.DependencyInjection" Version="4.0.0" />
<PackageReference Include="Shiny.Extensions.DependencyInjection" />
paket add Shiny.Extensions.DependencyInjection --version 4.0.0
#r "nuget: Shiny.Extensions.DependencyInjection, 4.0.0"
#:package Shiny.Extensions.DependencyInjection@4.0.0
#addin nuget:?package=Shiny.Extensions.DependencyInjection&version=4.0.0
#tool nuget:?package=Shiny.Extensions.DependencyInjection&version=4.0.0
Shiny Extensions
Dependency Injection Extensions
- Source generate all attributed classes to a single add file - saves you the boilerplate
- Factory-form emission - generated registrations expand the constructor at compile time (no reflection, AOT-clean) so resolve chains like
OnResolvedcompose naturally ActivatorUtilities-style constructor selection ([ActivatorUtilitiesConstructor]and[FromKeyedServices]honored)- Multiple interfaces via explicit forwarders (no reflection)
- Supports open generics and keyed services
OnResolved<T>(hook)chain extension for one-shot post-construction hooks
The Results
THIS:
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;
}
}
}
Setup
- Install the NuGet package
Shiny.Extensions.DependencyInjection - Add the following using directive:
// during your app startup - use your service collection builder.Services.AddGeneratedServices(); - Add the
[Service(ServiceLifetime.Singleton, "optional key")]attribute to your classes and specify the lifetime and optional key
Stores
- Cross-platform key/value store with support for
- Android/iOS/Windows - Preferences & Secure Storage
- Web - Local Storage
- In Memory
- Source-generated
[Bind]attribute on partial properties - emits getter/setter bodies that round-trip through the store (no INPC required, no runtime reflection, fully AOT) - Static
Shiny.Stores.Default/Secure/Keyed(...)accessor for direct ad-hoc reads/writes - Implement
IKeyValueStoreto plug in your own store
Setup
- Install the NuGet package
Shiny.Extensions.Stores - Register at startup — the static
Shiny.Storesaccessor self-bootstraps on first use:
On Blazor WebAssembly (wherebuilder.Services.AddShinyStores(); var host = builder.Build();LocalStorageKeyValueStoreneedsIJSRuntime), also callhost.Services.UseShinyStores()afterBuild()to snapshot the DI-resolved store into the static accessor. - Define your settings as a
partialclass 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; } } - Inject
AppSettingsanywhere. 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");
Available Stores Per Platform
| 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.
Web Hosting Extensions
- Merges service container build and post build scenarios into a single class using
IWebModule
Setup
- Install the NuGet package
Shiny.Extensions.WebHosting - Add a web module by implementing
IWebModule: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 } } - In your application hosting startup, add the following:
using Shiny; var builder = WebApplication.CreateBuilder(args); builder.AddInfrastructureModules(new MyWebModule()); var app = builder.Build(); app.UseInfrastructureModules();
MAUI Hosting Extensions
- Module-based MAUI app configuration with
IMauiModule - Static
Host.Servicesfor accessing the service provider anywhere IAppSupport— device info, 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)- Opt-in registration: each capability is its own extension method so apps only pay for what they use
Setup
- Install the NuGet package
Shiny.Extensions.MauiHosting - Create a MAUI module by implementing
IMauiModule: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) } } - In your
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(); - Access services anywhere via
Host.Services
IAppSupport
public class MyVm(IAppSupport app)
{
void Hook()
{
// Snapshot
var version = app.AppVersion;
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();
}
}
IAppStore
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();
}
Additional Libraries Used
- Shiny Reflector - Reflection without the actual reflection
NuGet Packages
| Package | Description |
|---|---|
Shiny.Extensions.DependencyInjection |
Attribute-driven DI registration with source generators |
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 |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
- Shiny.Extensions.Stores (>= 4.0.0)
NuGet packages (22)
Showing the top 5 NuGet packages that depend on Shiny.Extensions.DependencyInjection:
| 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 |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on Shiny.Extensions.DependencyInjection:
| Repository | Stars |
|---|---|
|
shinyorg/templates
dotnet CLI & Visual Studio Templates
|
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0 | 0 | 5/28/2026 |
| 4.0.0-beta-0063 | 0 | 5/27/2026 |
| 4.0.0-beta-0062 | 0 | 5/27/2026 |
| 4.0.0-beta-0061 | 0 | 5/27/2026 |
| 4.0.0-beta-0060 | 26 | 5/27/2026 |
| 4.0.0-beta-0059 | 38 | 5/27/2026 |
| 4.0.0-beta-0058 | 101 | 5/26/2026 |
| 4.0.0-beta-0057 | 35 | 5/26/2026 |
| 4.0.0-beta-0056 | 108 | 5/22/2026 |
| 4.0.0-beta-0041 | 125 | 5/18/2026 |
| 4.0.0-beta-0005 | 101 | 5/22/2026 |
| 4.0.0-beta-0004 | 116 | 5/20/2026 |
| 4.0.0-beta-0003 | 113 | 5/19/2026 |
| 4.0.0-beta-0002 | 115 | 5/18/2026 |
| 3.0.0 | 224 | 4/30/2026 |
| 2.1.0-beta-0045 | 119 | 4/3/2026 |
| 2.1.0-beta-0044 | 106 | 4/3/2026 |
| 2.1.0-beta-0043 | 117 | 3/18/2026 |
| 2.0.4 | 496 | 4/3/2026 |
| 2.0.3 | 183 | 3/18/2026 |