How to get Dotnet cache to keep values between API controller calls?

537 Views Asked by At

I have an API that is being used to return cache user profile data between a front end UI and a really slow backend API. The cache needs to be able to get the data from the backend API, cache it, and then serve it to the front end whenever the front end needs it.

The problem is that when the cache API is called, it gets the data, adds it to the cache and returns the data to the front end. However, on subsequent calls the cache claims to not have the data and re-fetches the data from the slow api. Is there a setting in Dotnet that I have to enable in order to force the cache to keep data between separate controller calls to the API? The API is acting as if a new cache is created on each controller call so the cache is always empty in the service.

Controller

     public async Task<IActionResult> getUser([FromBody] UserInput input)
        {
            try
            {                
                UserProfileResponse returned = await _userService.GetUserProfile(input);

                return Ok(returned);
            }
            catch (Exception ex)
            {
                return BadRequest($"Something went wrong. Message: {ex.Message}");
            }
        }

Service

public async Task<UserProfileResponse> GetUserProfile(UserInput input)
        {
            string key = Constants.USER_CACHE_PREFIX + "_" + input.Inputs.ID;
            _entryOptions = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove);
            
            // Check if the information is in the cache !!! The value is never found in the cache on subsequent calls !!!
            _ = this._cache.TryGetValue(key, out UserProfileResponse value);
            if (value != null)
            {
                return value;
            }

            // Prepare Endpoint Call
            var Config = _configuration.GetSection(Constants.Config);
            var endpoint = Config [Constants.endpoint];
            var function = Constants.function;

            // Call slow API service to get user profile
            UserProfileResponse result = await service.SendRequest<UserProfileResponse>(input, endpoint, function);

            if (result!= null)
            {
                this._cache.Set<UserProfileResponse>(key, result, _entryOptions);
            }
            
            return result;
        }

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
//... Code before
            services.AddHttpClient();
            services.AddControllers();
            services.AddMemoryCache();

            services.AddScoped<IMemoryCache, MemoryCache>();
            services.AddScoped<IDeserializeJson, DeserializeJson>();
            services.AddScoped<IUserService, UserService>();

//... Code after
}

1

There are 1 best solutions below

3
On BEST ANSWER

When you call AddMemoryCache() that should be sufficient for setting up your dependency injection container. Your later call to AddScoped<IMemoryCache, MemoryCache>() which is blowing away the service descriptor and overwriting it.

Removing the call to AddScoped<IMemoryCache, MemoryCache>() should make it behave normally.

AddScoped means to recreate the object with every scope. In the case of ASP.NET Core, that means every request gets a new memory cache (with an empty set of cache entries). The AddMemoryCache() method sets it up as a singleton, which is the correct configuration in this case.

You can see the code for AddMemoryCache() here.