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

Startup Services

Startup services run immediately after the dependency injection container is built. They support full constructor injection like any other service, which makes them the perfect place to hook global application events — wiring up a logout handler, warming a cache, subscribing to a message bus, or scheduling jobs.

IShinyStartupTask.Start() is intentionally synchronous. The platform does not wait for your app startup to finish, so any async work you kick off here runs in a fire-and-forget fashion. If you block for too long, the OS can kill your app before it finishes launching.

using Shiny;
namespace MyApp.Infrastructure;
public class MyStartupService : IShinyStartupTask
{
readonly ILogger<MyStartupService> logger;
public MyStartupService(ILogger<MyStartupService> logger)
{
this.logger = logger;
}
public void Start()
{
// Hook global events, warm caches, etc.
this.logger.LogInformation("App started");
}
}

Tag the class with [Singleton] from Shiny.Extensions.DependencyInjection and call services.AddGeneratedServices() once during host build. The source generator emits a registration that exposes every interface the class implements (including IShinyStartupTask) — no reflection, AOT-clean.

using Shiny;
[Singleton]
public class MyStartupService : IShinyStartupTask
{
// ...
}
// wherever you build your service collection
builder.Services.AddGeneratedServices();

If you prefer explicit registration:

builder.Services.AddSingleton<MyStartupService>();
builder.Services.AddSingleton<IShinyStartupTask>(sp => sp.GetRequiredService<MyStartupService>());

Either way, Start() runs automatically when the Shiny host runs.