Skip to content
Client v5: BLE, BLE Hosting, HTTP, Jobs - Linux, MacOS, & Blazor Support! Full AOT, RX on BLE only & MANY other features! Check It Out

Architecture

Shiny is built around three core concepts: Services, Delegates, and Events. These form the foundation of every Shiny library and understanding them will help you use Shiny effectively.

Shiny is designed as a unified framework — not a collection of independent plugins. Under the hood, it manages storage, logging, platform lifecycle hooks, and cross-platform utilities so you don’t have to.

AOT-first. As of v5, Reactive Extensions (Rx) has been removed from Shiny.Core, Shiny.Jobs, Shiny.Locations, Shiny.Net.Http, Shiny.Notifications, Shiny.Push, and Shiny.BluetoothLE.Hosting. Those modules now expose plain C# event EventHandler<T> for foreground notification. Shiny.BluetoothLE (client) retains IObservable<T> because reactive composition is genuinely useful when chaining GATT operations and managing scan lifecycles.

Services

Services are the primary API you interact with. They are registered with dependency injection and provide the interface for controlling platform features.

// Inject and use services directly
IGpsManager gpsManager; // injected
await gpsManager.StartListener(new GpsRequest
{
UseBackground = true
});

Services follow standard .NET DI patterns — register once, inject anywhere.

Delegates

Delegates are your callback handlers for background events. They are registered at startup and called by Shiny when platform events fire — even when your app isn’t in the foreground.

public class MyGpsDelegate : IGpsDelegate
{
public Task OnReading(IGpsReading reading)
{
// Handle GPS reading in background
}
}

Delegates support full dependency injection and are treated as singletons.

Events

Most Shiny modules expose plain C# event EventHandler<T> for foreground notifications — simple to consume, AOT-clean, and free of System.Reactive overhead.

gpsManager.GpsReadingReceived += (sender, reading) =>
{
if (reading.Speed > 10)
{
// foreground GPS handling
}
};

Events are ideal for UI binding and foreground scenarios. Shiny.BluetoothLE (client) retains IObservable<T> because reactive composition is genuinely useful for GATT pipelines and scan lifecycles.

1
RegisterAdd services and delegates to your DI container at startup
2
InteractInject services and call methods to start/stop platform features
3
ReactDelegates handle background callbacks; C# events stream foreground updates
// 1. Register at startup
services.AddGps<MyGpsDelegate>();
// 2. Interact via injected service
await gpsManager.StartListener(new GpsRequest(GpsBackgroundMode.Standard));
// 3. React — foreground via C# event
gpsManager.GpsReadingReceived += (s, reading) => { /* update UI */ };
// 3. React — background via delegate (called by Shiny automatically)
public class MyGpsDelegate : IGpsDelegate
{
public Task OnReading(GpsReading reading) => /* handle */;
}