Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

MAUI Hosting

Recommended for most apps

.NET MAUI is the recommended hosting model for Shiny. A single line of code wires up all platform lifecycle hooks, dependency injection, and background services — so you can focus on registering your Shiny modules.

  1. Install the NuGet package

    NuGet package Shiny.Hosting.Maui
  2. Add UseShiny() to your MauiProgram.cs

    using Shiny;
    namespace ShinyApp;
    public static class MauiProgram
    {
    public static MauiApp CreateMauiApp()
    {
    var builder = MauiApp
    .CreateBuilder()
    .UseMauiApp<App>()
    .UseShiny() // <-- this wires all Shiny lifecycle through MAUI
    .ConfigureFonts(fonts =>
    {
    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
    });
    // Register your Shiny services here
    // builder.Services.AddGps<MyGpsDelegate>();
    // builder.Services.AddJob(typeof(MyJob));
    return builder.Build();
    }
    }
  3. Register Shiny services

    Use builder.Services to register any Shiny modules you need — GPS, Bluetooth, Jobs, Notifications, etc. See each module’s Getting Started page for specifics.

Nothing extra is needed. Mac Catalyst is a first-class MAUI target — UseShiny() handles it the same way it handles iOS.

Native macOS (AppKit) uses MAUI’s macOS backend — not Mac Catalyst, not UseShiny(). Create an NSApplication entry point that uses MacOSMauiApplication as the delegate, call UseMauiAppMacOS<App>() + AddMacOSEssentials() in MauiProgram, and register Shiny services directly on builder.Services:

Main.cs
using AppKit;
using Microsoft.Maui.Platform.MacOS.Hosting;
using Shiny.Hosting;
public class Program
{
static void Main(string[] args)
{
NSApplication.Init();
NSApplication.SharedApplication.Delegate = new AppDelegate();
NSApplication.Main(args);
}
}
public class AppDelegate : MacOSMauiApplication
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
// Forward these only if you're using Shiny.Push
[Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
public void DidRegisterForRemoteNotifications(NSApplication app, NSData deviceToken)
=> Host.Lifecycle.OnRegisteredForRemoteNotifications(deviceToken);
[Export("application:didFailToRegisterForRemoteNotificationsWithError:")]
public void DidFailToRegisterForRemoteNotifications(NSApplication app, NSError error)
=> Host.Lifecycle.OnFailedToRegisterForRemoteNotifications(error);
[Export("application:didReceiveRemoteNotification:")]
public void DidReceiveRemoteNotification(NSApplication app, NSDictionary userInfo)
=> Host.Lifecycle.OnDidReceiveRemoteNotification(userInfo);
}
MauiProgram.cs
using Microsoft.Maui.Essentials.MacOS;
using Microsoft.Maui.Platform.MacOS.Hosting;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiAppMacOS<App>()
.AddMacOSEssentials();
// Register Shiny modules directly — no UseShiny() on native macOS
builder.Services.AddBluetoothLE();
builder.Services.AddNotifications();
return builder.Build();
}
}

Shiny modules with native macOS support: BLE, BLE Hosting, Notifications, Push, Battery, Connectivity.

Linux does not need UseShiny() — there are no native lifecycle hooks to wire up. Use the MAUI GTK4 entry point and register Shiny services directly on builder.Services:

var builder = MauiApp.CreateBuilder();
builder
.UseMauiAppLinuxGtk4<App>()
.AddLinuxGtk4Essentials();
// Register Shiny modules directly — no UseShiny() required on Linux
builder.Services.AddBluetoothLE();
builder.Services.AddNotifications();

Shiny modules with Linux support: BLE, BLE Hosting, Notifications, Mediator, Stores, Localization, Document DB, Reflector, DI.

Blazor does not use UseShiny() — there is no native platform lifecycle to wire. Register Shiny modules directly on builder.Services in your Blazor Program.cs:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddBluetoothLE();
builder.Services.AddGps();
builder.Services.AddPush(new WebPushOptions { VapidPublicKey = "..." });
await builder.Build().RunAsync();

Third-party DI containers (Prism, DryIoc, Autofac)

Section titled “Third-party DI containers (Prism, DryIoc, Autofac)”

Shiny registers everything through the standard IServiceCollection, so any container with a Microsoft.Extensions.DependencyInjection adapter works — including Prism’s DryIoc container. There is one caveat worth knowing about.

Shiny’s key/value stores are registered as keyed services (StoreKeys.Default, StoreKeys.Secure) and Shiny’s own types inject them with [FromKeyedServices(StoreKeys.Default)]. Keyed services arrived in .NET 8, and several container adapters still ship a pre-keyed-services core — Prism.Container.DryIoc, for example, is built on DryIoc 5.x. Those adapters silently ignore the [FromKeyedServices] attribute and try to resolve the plain service type instead.

AddShinyStores() handles this by also registering the default store unkeyed, pointing at the same instance as StoreKeys.Default, so Shiny’s platform types resolve correctly on those containers.

There is no equivalent fallback for StoreKeys.Secure — two stores can’t share one unkeyed service type. In your code, avoid [FromKeyedServices] for the secure or custom stores when the app uses a non-Microsoft container, and use the static accessor instead:

// works on every container
var token = Shiny.Stores.Secure.Get<string>("token");
var custom = Shiny.Stores.Keyed("my-store");
Scenario Hosting Model
Standard .NET MAUI app MAUI (this page)
.NET native without MAUI (iOS/Android) Native
Existing app with complex platform setup Manual