Singleton Class with Async

GarudaLead-8570 46 Reputation points
2025-05-15T12:19:30.1366667+00:00

I'm working on building a Blazor Web App (.net 9) for an internal company portal.

I want to load some persistent data to be used throughout the app into a class and then load that class as a scoped service.

Most of the data will be fairly static, but expensive data to retrieve, ie: graph api call for members of groups, etc. So that data will also be loaded asynchronously.

Everything I've found regarding loading data into a class asynchronously basically points back to a post by Stephen Cleary on Asynchronous Lazy Initialization: https://blog.stephencleary.com/2012/08/asynchronous-lazy-initialization.html

My question is, given that this post was originally posted back in 2012, is this still an acceptable way of loading data asynchronously for a singleton or are there other, more modern approaches to this scenario?

Developer technologies ASP.NET ASP.NET API
{count} votes

3 answers

Sort by: Most helpful
  1. GarudaLead-8570 46 Reputation points
    2025-05-15T12:54:31.8466667+00:00

    I believe I posted this to the wrong forum.

    0 comments No comments

  2. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2025-05-15T16:12:04.92+00:00

    this code is still valid, but it uses a static, which you would not use with Blazor server, as it would be shared with all users (unless its the same for all instances).

    also with Blazor, you need to take into account pre-render. the pre-render Blazor instance is different from the runtime instance, so the service will be created twice.

    If the pre-render does all the work of loading, you might want to pass the data to runtime instance via persist pre-render state functions. the save works by writing the state as json to the client on pre-render, then if Blazor Server, the client sends the json back to the server, you don't want it too large. Blazor WASM just loads the json state.

    https://learn.microsoft.com/en-us/aspnet/core/blazor/components/prerender?view=aspnetcore-9.0

    0 comments No comments

  3. Jack Dang (WICLOUD CORPORATION) 225 Reputation points Microsoft External Staff
    2025-06-27T08:54:51.2533333+00:00

    Hi @GarudaLead-8570 ,

     

    Thanks for the great question! You're addressing a common challenge in Blazor apps—efficiently loading expensive data while keeping your architecture clean and responsive.

     

    Is Stephen Cleary’s AsyncLazy Still Valid?

    Yes, Stephen Cleary’s AsyncLazy<T> pattern is still a valid and effective solution for lazy asynchronous initialization. It ensures that expensive operations (like API calls) are only executed once and in a thread-safe manner. This is especially useful when you want to defer loading until the data is actually needed.

     

    Regarding your case, here are some modern recommendations for your scenario:

    1. Scoped vs Singleton

    • Use a scoped service if the data is user-specific (e.g., Graph API data tied to the logged-in user).
    • Use a singleton service only if the data is shared across all users and sessions.

    2. Avoid Static in Blazor Server

    Avoid using static fields or properties for storing data in Blazor Server apps, as they are shared across all users. This can lead to data leakage or incorrect behavior unless the data is truly global and identical for all users.

    3. Prerendering Considerations

    • Blazor Server uses prerendering to generate HTML before the app becomes interactive. This means your services may be instantiated twice—once during prerendering and again during runtime.
    • If your service loads data during prerendering, you may want to persist that state and pass it to the runtime instance to avoid duplicate loading.

    4. Persisting Pre-rendered State

    • You can use Blazor’s persisted state feature to serialize data (as JSON) during prerendering and send it back to the server when the app becomes interactive.
    • This avoids re-fetching data and improves performance, but be mindful of the size of the JSON payload, especially in Blazor Server.

    5. Async Initialization Pattern

    • Avoid async constructors. Use an explicit InitializeAsync() method or lazy-loading pattern like AsyncLazy<T>.
    • Ensure proper error handling and consider retry logic for external API calls.

     

    Summary

    • Yes, AsyncLazy<T> is still a solid choice.
    • Use scoped services for user-specific data, and avoid static in Blazor Server.
    • Be aware of prerendering behavior—services may be created twice.
    • Use persisted state to pass data from prerender to runtime if needed.
    • Prefer explicit async initialization or lazy async loading.

    Hope my answer would help. If you have extra questions, please click "Comment".

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.