Skip to content
Document DB v8.0 Interceptors, Temporal Support, Telemetry Collection, All Calculations, String Based APIs, & Orleans Storage Providers! Feed The Machine Here

Push (Server)

Server-side push notification dispatch for .NET. A provider-agnostic core with a direct APNs transport (token-based .p8 / ES256 over HTTP/2 — no FCM dependency for Apple), pluggable persistence (Shiny.DocumentDb), structured targeting, an interceptor pipeline, automatic dead-token pruning, multi-app keyed registration, and System.Diagnostics.Metrics telemetry. The whole library is AOT/trim-safe.

Frameworks
.NET
ASP.NET
CoreNuGet downloads for Shiny.Extensions.Push
APNsNuGet downloads for Shiny.Extensions.Push.Apns
DocumentDbNuGet downloads for Shiny.Extensions.Push.DocumentDb
  • Provider-agnostic core — one IPushManager; transports plug in as IPushProvider
  • Direct APNs — HTTP/2, token-based .p8 / ES256 JWT auth, per-registration sandbox/production
  • Structured, AOT-safe targeting — send to a user, tags/segments, explicit tokens, or broadcast
  • Rich payloads — title/body, badge, sound, deep link, collapse id, TTL, silent/background pushes, plus per-platform escape hatches (ApplePushOptions, AndroidPushOptions, WebPushOptions)
  • Automatic token hygiene — expired/invalid tokens are pruned; rotated tokens are applied back
  • Interceptors — localize, personalize, or suppress per device
  • Batching / FCM multicast — batch-capable transports deliver many devices per call (FCM: up to 500 per /batch request); on by default via IPushBatchProvider
  • Multi-app — keyed registrations serve several apps from one server
  • Metrics — counters + latency histogram via System.Diagnostics.Metrics (OpenTelemetry-ready)
  • Pluggable persistence — in-memory out of the box, or Shiny.DocumentDb on any backend

Install the core plus the transport and (optionally) a persistence package:

Terminal window
dotnet add package Shiny.Extensions.Push
dotnet add package Shiny.Extensions.Push.Apns
dotnet add package Shiny.Extensions.Push.DocumentDb # optional; defaults to in-memory

Register the service:

using Shiny.Extensions.Push;
using Shiny.Extensions.Push.Apns;
using Shiny.Extensions.Push.DocumentDb;
using Shiny.DocumentDb.Sqlite;
builder.Services.AddPushNotifications(push =>
{
push.AddApns(o =>
{
o.TeamId = "ABCDE12345";
o.KeyId = "KEY1234567";
o.BundleId = "com.example.app";
o.PrivateKeyPath = "AuthKey_KEY1234567.p8"; // or o.PrivateKey = "<PEM contents>"
});
// Persistence (omit to use the in-memory repository)
push.UseDocumentDb(o => o.DatabaseProvider = new SqliteDatabaseProvider("Data Source=push.db"));
});

Register a device when your app reports its token:

await pushManager.RegisterDevice(new DeviceRegistration
{
DeviceToken = "<apns-device-token>",
Platform = DevicePlatform.iOS,
DeviceId = "install-guid", // stable identity across token rotation
UserIdentifier = "user-42",
Tags = ["beta", "sports"],
Environment = PushEnvironment.Production // APNs tokens are environment-specific
});

Send:

var result = await pushManager.SendToUser("user-42", new PushNotification
{
Title = "Goal!",
Message = "Your team just scored",
Badge = 1,
DeepLink = "app://match/123"
});
// result.BatchId, result.Sent, result.Failed, result.TokensRemoved, result.Skipped

Next: Sending, APNs, Persistence, Metrics.