As mentioned earlier, all services you create must be registered in Program.cs, but some basic services don't require manual setup.
Currently, Blazor provides three built-in services:
HttpClient: Handles HTTP requests, with a Scoped lifetime (Note: Only available in Blazor WebAssembly; for Blazor Server, you must register it yourself).IJSRuntime: Provides the JavaScript runtime component for JS functionality. For Blazor WebAssembly, the lifetime isSingleton; for Blazor Server, it isScoped.NavigationManager: Handles route navigation and state. For Blazor WebAssembly, the lifetime isSingleton; for Blazor Server, it isScoped.
Lifetime refers to the duration a component exists. Besides Singleton and Scoped, there is also Transient.
Singleton: Only one instance exists from application start to shutdown, shared by all components.Transient: A new instance is created every time the component is used.Scoped: This is special because Blazor Server and Blazor WebAssembly behave differently. In Blazor Server,Scopedmeans a new instance is created per HTTP request, but components communicating via SignalR do not create new instances. Microsoft documentation states, "Blazor WebAssembly does not currently have the concept of DI;Scopedis equivalent toSingleton."
However, I was also confused after reading the above explanation, until I watched a video using GUIDs to demonstrate. Let's try it out.
First, create an interface IGuidService with a single string property UId. Then create a class GuidService and initialize the UId property as a GUID string in the constructor. Next, register it in Program.cs using AddTransient.

Then create a Guid.razor component with three lines: define a route, inject the service, and display the GUID string. Since this example is simple and doesn't use ComponentBase, add @using BlazorServer.Services to _Import.razor. Finally, for easy navigation, define a set of NavLink in NavMenu.razor pointing to the newly created Guid.razor.

After starting, whether switching between the Post and Guid pages or reloading the page, you will see a new set of GUID generated each time. This is the characteristic of Transient: a new instance is created on every switch.

Next, change the registration to Singleton. Even after reloading the page, you see the same GUID. This is the characteristic of Singleton: only one instance exists from application start to shutdown.

Finally, change the registration to Scoped. Switch to the Post page and back – still the same GUID. But when you reload the page, a new set appears. This is the characteristic of Scoped: each HTTP request creates a new instance, but components do not create new instances among themselves.

The above example uses Blazor Server. If using Blazor WebAssembly, Singleton behaves differently from Blazor Server because Blazor WebAssembly has no server side. Every time the page is reloaded, the application downloads to the browser as a completely new HTTP request. Therefore, both Singleton and Scoped create a new instance whenever the page is reloaded.


Note: For brevity, I omitted some content from the video. Interested readers can explore further.
References:
- Blazor Course - Use ASP.NET Core to Build Full-Stack C# Web Apps
- ASP.NET Core Blazor dependency injection
Note: The code in this article is refactored using .NET 6 + Visual Studio 2022. You can click the original link to compare with the refactored code. Thanks for reading and supporting the original author.