Lifetime Scope in Blazor Client and Server Apps

11/24/2021
4 minute read

Short Summary

We basically know 3 types of lifetimes when it come to ASP.NET Core

  • Singleton - One instance is created and is shared across all users
  • Transient - Whenever someone is asking for a service always a new instance is created
  • Scoped - One instance per request

Setup

Let's create three services, for each lifetime one:

public class MySingletonService
{
    public Guid ServiceId { get; set; } = Guid.NewGuid();
}

public class MyScopedService
{
    public Guid ServiceId { get; set; } = Guid.NewGuid();
}

public class MyTransientService
{
    public Guid ServiceId { get; set; } = Guid.NewGuid();
}

Now we need two pages. We reuse the template which comes shipped with Visual Studio. Therefore we adapt the Index.razor and Counter.razor in this way:

@page "/"
@inject MySingletonService singletonService
@inject MyScopedService scopedService
@inject MyTransientService transientService

<h1>Index</h1>
<ul>
    <li>Singleton Service - @singletonService.ServiceId</li>
    <li>Scoped Service - @scopedService.ServiceId</li>
    <li>Transient Service - @transientService.ServiceId</li>
</ul>
@page "/"
@inject MySingletonService singletonService
@inject MyScopedService scopedService
@inject MyTransientService transientService

<h1>Counter</h1>
<ul>
    <li>Singleton Service - @singletonService.ServiceId</li>
    <li>Scoped Service - @scopedService.ServiceId</li>
    <li>Transient Service - @transientService.ServiceId</li>
</ul>

They look the same only the header is different. Now we want to check a few scenarios:

  • Start the app and land on our home page
  • Navigate to the counter page from the navigation menu
  • Reload the index page with F5
  • Open the page in incognito mode

Blazor Client

Now we have a look how the ID's look on the client side

Home page Navigate to counter Hard reload Incognito mode
Singleton 17bbf702-b870-4242-a016-53440d85c30c 17bbf702-b870-4242-a016-53440d85c30c 2cde0cc6-792d-4f24-8752-6662996e506b 9ed59027-9a43-45ec-827e-2bc6e8fcde5c
Scoped 5526f6ea-0bfe-44fe-8264-a902286ec165 5526f6ea-0bfe-44fe-8264-a902286ec165 ada9205d-af01-4c1b-86b5-de840f02cce5 7b6283d1-fdef-4a49-850d-c1a78111a849
Transient 96707761-be74-4cf7-94d6-3fc940f9d016 732ed661-e833-4537-a7bf-9691f81d58bd f218f73b-93b7-43d6-9cf2-f9a08960c489 036b450b-c486-49e5-9a9c-07b22f4e5713

Now let's have a look. First the obvious one: Transient. I guess it is not weird that all of the services are unique. Now let's come to Singleton. Why is it different for Hard reload and incognito? The answer is easy: The code runs on your local machine and not on a server, therefore this is basically like a new program running which initializes the container once more. Now Scoped: Why do we have the same ID when we navigate to a different page? Well that is the idea behind a single page application. You don't make a new "request". You are still in the same request as you started. That also explains why a hard reload gives you a new ID, because now we have a new request.

Let's go to the server side

Blazor Server

Home page Navigate to counter Hard reload Incognito mode
Singleton 76844a38-eca3-4b75-b47a-1f3bbc5510c9 76844a38-eca3-4b75-b47a-1f3bbc5510c9 76844a38-eca3-4b75-b47a-1f3bbc5510c9 76844a38-eca3-4b75-b47a-1f3bbc5510c9
Scoped a434c2f8-6e15-4787-bfc8-530cc1aebc9e a434c2f8-6e15-4787-bfc8-530cc1aebc9e 16f56278-38bc-4c88-a804-38d8682c655a e3d32065-f79f-4812-adc1-5b8ad9176e0c
Transient ad787879-a91e-4721-820b-95481cd90a85 55a993dd-22de-42e5-ad92-4e69666462e6 b4a5e6b2-5eb6-494d-b8df-9a9c763ca5c3 8fc3bc62-c4f8-4794-8ef6-6ff0b963950b

The not surprising part first: We have the same picture for Transient in client as well as server. If we have a look at the Singleton we see a difference. The incognito mode does not lead to a new instance. And that makes sense, because actually the server is the same. Blazor server "just" opens a SignalR connection with the HTML content rendered by the server. The main book of work is done on the server. Last but not least Scoped. We see the exact same picture as with the client side blazor. Of course client and server share a lot of similarities and this is also true for the Scoped lifetime.

Conclusion

Blazor client and server have a slightly different lifetime scope than your "normal" ASP.NET Core Web API or MVC project.

.NET 8 and Blazor United / Server-side rendering

New .NET and new Blazor features. In this blog post, I want to highlight the new features that are hitting us with .NET 8 in the Blazor world. So let's see what's new.

Blazor Client - Loading Screen

If you are using Blazor WebAssembly aka client-side Blazor you are faced with an issue: The .NET runtime including your assemblies has to be downloaded first. We are taking about some megabytes as the initial load.

Depending on the connection of your client there is a time where basically nothing happens. The default template just has a simple "Loading..." text. So let's change that.

Prerendering Blazor Apps - How does it work / tips and tricks

Blazor comes with the option to prerender your webpage on the server. This works for the client-side version as well as the server side version of Blazor.

Let's have a look how does it work and what might be some pitfalls and how can we come around those.

An error has occurred. This application may no longer respond until reloaded. Reload x