1
votes

I am trying to understand options and most optimal method to keep and access cached global app parameters in a Blazor Server app.

I've just recently started looking into Blazor so fairly new to this and might be thinking completely wrong direction here so any input to guide me in the correct direction is greatly appreciated.

Basically, I am thinking of a set of global app settings which are not likely to change often so no point reading db on each request. Hence, I am thinking of something similar to what in the old days in the world of .NET might look like a function in a controller for instance (simplified for review):

 protected IGlobalSettings getGlobalSettings() 
 {
        globalSettings = HttpContext.Application["appSettings"] as IGlobalSettings;

        if(globalSettings == null)
        {
            using (globalConfigurator _gc = new globalConfigurator())
            {                
                globalSettings = _gc.configureSettings();
                HttpContext.Application["appSettings"] = globalSettings;
            }
        }

        return globalSettings;
}

I understand in .NET Core, I can work with IMemoryCache service provided by DI, something that might look like:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private IMemoryCache _cache;

    public HomeController(ILogger<HomeController> logger, IMemoryCache memoryCache)
    {
        _logger = logger;
        _cache = memoryCache;
    }

    public globalSettings getCachedData()
    {
        if (_cache.Get("appSetings") is not globalSettings _globalSettings)
        {
            using (globalConfigurator _gc = new globalConfigurator())
            {                
                _globalSettings = _gc.configureSettings();
                _cache.Set("appSetings", _globalSettings);
            }
        }
        
        return _globalSettings;
    }
}

The idea here is - globalSettings object is accessible and consumed by all users across the app (I will not worry about distributed cache for now as well as issues of synchronization and keeping globalSettings data thread-safe). When it comes to Blazor components (or .NET Core razor pages for that matter) - what is the best way to make globalSettings object available in all pages that might require access to that data?

Ideally, I would like to have a service that provides globalSettings object and encapsulates extraction from cache or pulling from database in case object is not available from cache. Is this a good candidate for a middleware? In this case, this middleware will need access to IMemoryCache service.

Another question which I seem to struggle with is: how can I use the middleware in the components (pages) to set initial state of page class instance? Something like this where a DI provided service will pull a global settings object for the page:

@page "/AppConfigSettings"

@inject IGlobalSettingsProvider settingsProvider 

<div class="row">
    <span><strong>Parameter #1</strong>@settings.parameterOne</span><br />
    <span><strong>Parameter #1</strong>@settings.parameterTwo</span><br />
    <span><strong>Parameter #1</strong>@settings.parameterThree</span><br />
</div>

@code {
    globalSettings settings = settingsProvider.globalSettings();
}

where IGlobalSettingsProvider service will run a pull of the cached object from IMemoryCache or construct if the object in not in the cache.

I am not sure how far off i am here, again any bright ideas are much appreciated.

Thank you.

1
Blazor server-side or Blazor WebAssembly? - Henk Holterman
Henk, i was particularly looking into server-side. for this scenario - i will not worry about what is happening on the browser side. basically, the idea is to be able to handle a bunch of global app-data which is small enough and not changing frequently so a) inexpensive to keep in-memory and b) be able to save a trip to DB. with this in mind, i would like to be able to use that data to set initial state of Razor component instance objects as they get sent to the browser. - Yan D

1 Answers

2
votes

I would like to have a service that provides globalSettings object and encapsulates extraction from cache or pulling from database in case object is not available from cache. Is this a good candidate for a middleware?

The service is the right approach, but middleware is not applicable. Blazor uses a SignalR connection, not Http requests to display its pages.

Your Cache approach is largely Ok though:

class GlobalSettingsProvider
{
    public GlobalSettingsProvider(IMemoryCache cache)
    {
       _cache = cache;
    }

    public GlobalSettings GetSettings()
    {
        return _cache.GetOrCreate("appSetings", entry => 
         {
             // configure timeout
             return new GlobalSettings();  // configure
         });
    }
}

In Startup.ConfigureServices:

services.AddTransient<GlobalSettingsProvider>();

and in your pages:

@inject GlobalSettingsProvider GlobalSettingsProvider