Absolute expiration invalidates a cache entry at a fixed time or after a fixed duration. A board-game API can cache each filtered result for 30 seconds, then query EF Core again. section 8.3.3
Apply absolute expiration through a cache-or-query flow:
- Build a cache key from the request parameters so different queries receive different entries. section 8.3.3
- Call IMemoryCache.TryGetValue with the key; return the cached board-game array when it exists. section 8.3.3
- When the key is absent, retrieve results with EF Core and store them with an absolute expiration of 30 seconds. section 8.3.3
Filtered board-game requests
A request containing different GET parameters produces a different serialized cache key. The first request queries the database and caches its result; repeated requests can use that result until 30 seconds have elapsed. Breakpoints verify whether the cache path or database path runs. section 8.3.3
Listing 8.6 BoardGamesController’s Get method
[HttpGet(Name = "GetBoardGames")]
[ResponseCache(CacheProfileName = "Any-60")]
public async Task<RestDTO<BoardGame[]>> Get(
[FromQuery] RequestDTO<BoardGameDTO> input)
{
_logger.LogInformation(CustomLogEvents.BoardGamesController_Get,
"Get method started.");
var query = _context.BoardGames.AsQueryable(); #1
if (!string.IsNullOrEmpty(input.FilterQuery)) #2
query = query.Where(b => b.Name.Contains(input.FilterQuery));
var recordCount = await query.CountAsync(); #3
BoardGame[]? result = null; #4
var cacheKey = $"{input.GetType()}-{JsonSerializer.Serialize(input)}";#5
if (!_memoryCache.TryGetValue<BoardGame[]>(cacheKey, out result)) #6
{
query = query #7
.OrderBy($"{input.SortColumn} {input.SortOrder}")
.Skip(input.PageIndex * input.PageSize)
.Take(input.PageSize);
result = await query.ToArrayAsync();
_memoryCache.Set(cacheKey, result, new TimeSpan(0, 0, 30));
}
return new RestDTO<BoardGame[]>()
{
Data = result, #8
PageIndex = input.PageIndex,
PageSize = input.PageSize,
RecordCount = recordCount,
Links = new List<LinkDTO> {
new LinkDTO(
Url.Action(
null,
"BoardGames",
new { input.PageIndex, input.PageSize },
Request.Scheme)!,
"self",
"GET"),
}
};
}
Inspect the complete Get method, including query construction, JSON-based cache-key creation, cache lookup, and conditional database access. section 8.3.3
