dependency-injectionblazorsingletonblazor-webassembly

Accessing dbcontext in Constructor of Singleton Service


Scenario

In the server project of a Blazor web assembly application, I have a service that will utilize certain metadata from the database. This metadata will only change with changes to the schema - not during normal application execution.

My intent is to create a singleton service that can be called from a controller to access this information. I intend to capture this metadata once and then make it available through the service.

I believe the way to do this is to make the DbContext available within the constructor of the service, capture the information, and then destroy the DbContext as it will not be needed again within the service. Other methods will pass this metadata to the caller.

Question 1

Does this approach make sense? The basic logic will be:

public ServiceConstructor()
{
    // Get copy of the dbcontext
    // Do some work using the dbcontext
    // destroy the dbcontext.
}

Question 2

How do I go about getting a copy of the DbContext from the scoped service and does it make sense to do this without passing it in to the constructor as a parameter?


Solution

  • My approach would be to cache the data in a Singleton Service, but access it through a Scoped Service.

    The first Scoped Service to access the data finds it empty so gets it using a DBContext from the DbContextFactory. Thereafter any further scoped services access the data cached in the Singleton.

    I wouldn't pass a DbContext into the singleton for it to use.

    Something like:

    public class DataSingletonService
    {
        internal string? Value { get; private set; }
    
        internal void SetData(string value)
            => Value = value;
    }
    

    And

    public class DataScopedService
    {
        private DataSingletonService _dataSingletonService;
        // define the DBContextFactory here
    
        public DataScopedService(DataSingletonService dataSingletonService)
        {
            // Get the DBContextFactory here
            _dataSingletonService = dataSingletonService;
        }
    
        public async ValueTask<string> GetDataAsync()
        {
            if (_dataSingletonService.Value is null)
            {
                // using dbContext =  DbContextFactory.GetContext();
                // fake a db async call to the DbContext
                await Task.Delay(500);
                _dataSingletonService.SetData("Now Set");
            }
    
            return _dataSingletonService.Value ?? string.Empty;
        }
    }