dotnet / dotnet/dotnet-api-docs
Setting SlidingExpiration on a CacheEntry has some seemingly undocumented behavior
- Dominant language
- C#
- Stars
- 949
- Forks
- 1.7k
- Avg merge
- 3d 27m
- Merged PRs (30d)
- 49
Description
### Description
👋🏽 Wanted to preface this by saying: First time opening an issue here, please correct me if I misspeak.
This issue stems from the implementation of the `Microsoft.Extensions.Caching.Memory` package, and from the looks of it, specifically on `CacheEntry`. While looking into this issue, I wanted to make sure someone else hadn't already reported it, but the closest I could find regarding this exact issue is a question (posted [here](https://github.com/dotnet/runtime/issues/33188)).
When setting an *absolute* expiration, it makes sense that when that expiration passes, the object is removed, and this behavior also extends to sliding expirations, of which presumably get reset when the value is retrieved. This is fine, expected, and documented behavior. The documentation seems to be lacking in the nuance of sliding expirations, though.
If a sliding expiration is set, and an absolute expiration is absent, the sliding expiration then acts as an "absolute" expiration (from the time the object is inserted, it seems?). This is slightly confusing, at least to myself, since if the object is never "accessed", the sliding expiration cannot kick in.
### Reproduction Steps
```cs
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
namespace MinimalRepro;
public static class Program
{
public static async Task Main()
{
var services = new ServiceCollection();
services.AddMemoryCache();
var provider = services.BuildServiceProvider();
var cache = provider.GetRequireService();
var cacheOptions = new new MemoryCacheEntryOptions()
cacheOptions.SetSlidingExpiration(TimeSpan.FromSeconds(5));
cache.Set("example_key", "example_value", cacheOptions);
await Task.Delay(TimeSpan.FromSeconds(5));
var keyExists = cache.TryGetValue("example_key", out _);
if (!keyExists)
Console.WriteLine("The cached value has gone missing!");
}
}
```
### Expected behavior
The expiration timer is started when the value is initially accessed.
### Actual behavior
The object will expire from cache regardless of whether it's been "accessed"; this is likely due to the `LastAccessed` property of a CacheEntry being a non-nullable `DateTime`, which appears to default to `1/1/0001 12:00:00 AM`.
### Regression?
I'm unsure, but I'm doubtful of it.
### Known Workarounds
_No response_
### Configuration
.NET 6.0.100
Windows 10, 21H1, 64-bit.
This issue should be platform-agnostic.
### Other information
The issue is within [this code](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Caching.Memory/src/CacheEntry.cs#L181-L207), and I believe is due to the issue regarding the datetime being initialized with a default value that will almost always be greater than the expiration, or so I'd hope 😄.
While I wouldn't say that this is a *bug* or incorrect behavior, I think at the very least the documentation ([MSDN Link](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.memory.icacheentry.slidingexpiration?view=dotnet-plat-ext-6.0)) should be updated to reflect this otherwise undocumented behavior.
Contributor guide
Assessment
This issue has not been assessed yet.