In this lesson, you will learn how to configure service lifetimes in the Blazor Dependency Injection (DI) container and why the behavior changes depending on whether you are running in Blazor Server or Blazor WebAssembly.
Service Lifetimes in DI
The DI container manages the creation and disposal of your services. You register these in your Program.cs file using three primary lifetimes:
- Transient (
AddTransient): A new instance is created every time the service is requested. - Scoped (
AddScoped): A single instance is created per user session. - Singleton (
AddSingleton): A single instance is created the first time it is requested and shared across the entire application.
Blazor Server vs. WebAssembly
While the syntax builder.Services.AddScoped<IMyService, MyService>() looks identical in both environments, the "scope" itself behaves differently:
Blazor Server
In Blazor Server, a Scoped service is tied to the individual user’s circuit (the SignalR connection). If a user refreshes their browser, the circuit is destroyed and a new scope is created. This makes AddScoped perfect for storing user-specific data that should persist throughout a single browser session but reset upon a refresh.
Blazor WebAssembly
In WebAssembly, there is only one user per browser instance, and the app runs entirely in the client's browser memory. Consequently, Scoped services behave almost identically to Singleton services; the "scope" lasts for the lifetime of the browser tab. If the user refreshes, the entire application (including the DI container) is reloaded from scratch.
Implementation Example
You configure these in your Program.cs:
// Registering services with different lifetimes
builder.Services.AddTransient<ILoggerService, LoggerService>();
builder.Services.AddScoped<IUserSessionService, UserSessionService>();
builder.Services.AddSingleton<IGlobalConfigService, GlobalConfigService>();
When injecting these into your components via the @inject directive, the container automatically resolves the correct instance based on these definitions. Understanding this distinction is vital for managing state correctly—using Scoped to store data in WebAssembly will not protect you against a page refresh, whereas in Server mode, it will keep data isolated per user.
Key Takeaway: While DI registration syntax is consistent across Blazor, remember that "Scoped" behaves as a session-level container in Blazor Server but acts as a global singleton within the browser's memory in Blazor WebAssembly.