0

I have a method that will expire null items immediately, however I wanted to know if there w as better way to do this for all memory cache items instead of repeating the same code over and over

output = _cache.GetOrAdd("GetRecordUri" + 123, entry =>
{
    var record = internalGetRecordUri();
    if (record == null)
        // expire immediately
        entry.AbsoluteExpirationRelativeToNow = new TimeSpan(-1, 0, 0, 0);
    else
        entry.AbsoluteExpirationRelativeToNow = new TimeSpan(1, 0, 0, 0);
    return record;
});

The code in bold seems redundant Is there an extension that I can use that will do the same?

2
  • Your code throws to me an ArgumentOutOfRangeException: The relative expiration value must be positive. on the line that assigns the entry.AbsoluteExpirationRelativeToNow to the value new TimeSpan(-1, 0, 0, 0). Commented Jun 13, 2022 at 19:10
  • Same exception for me, this does not work in .NET 6. entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(-1); fails, as does entry.AbsoluteExpirationRelativeToNow = TimeSpan.Zero; But if you do entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(-1); then you get away with it. It's still a bit of hack. Commented Jul 8, 2023 at 10:56

2 Answers 2

1

It would be nice if you could signal in addtemFactory that the value is not to be cached at all, e.g.

output = _cache.GetOrAdd("GetRecordUri_" + id, entry =>
{
    var record = internalGetRecordUri(id);
    if (IsError(record))
        entry.IsValidToCache = false; //  not actual
    return record;
});

But there is no such mechanism, without throwing an exception.

Setting the AbsoluteExpirationRelativeToNow to a zero or negative value does not work, it throws a ArgumentOutOfRangeException:

System.ArgumentOutOfRangeException
  Message=The relative expiration value must be positive. (Parameter 'AbsoluteExpirationRelativeToNow')
Actual value was 00:00:00.
  Source=Microsoft.Extensions.Caching.Memory
  StackTrace:
   at Microsoft.Extensions.Caching.Memory.CacheEntry.set_AbsoluteExpirationRelativeToNow(Nullable`1 value)

Throwing an exception in the addtemFactory, is however supported and effective to prevent caching of the result: "LazyCache Stops you inadvertently caching an exception by removing Lazys that evaluate to an exception". I recommend using a more meaningful exception type than a ArgumentOutOfRangeException

e.g.

output = _cache.GetOrAdd("GetRecordUri_" + id, entry =>
{
    var record = internalGetRecordUri(id);
    if (IsError(record))
        throw new SomeException("GetRecordUri failed for " + id); // actual
    return record;
});

You just have to now think about where the exception is caught.

Sign up to request clarification or add additional context in comments.

Comments

0

You can place this check in separate method:

public void SetAbsoluteExpiration(Entry entry, object value) // change Entry to correct type
{
    if (value is null) // or if (value == null)
        // expire immediately
        entry.AbsoluteExpirationRelativeToNow = new TimeSpan(-1, 0, 0, 0);
    else
        entry.AbsoluteExpirationRelativeToNow = new TimeSpan(1, 0, 0, 0);
}

And call it everywhere you need:

 output = _cache.GetOrAdd(
    "GetRecordUri" + 123, entry => {
        var record = internalGetRecordUri();
        
        SetAbsoluteExpiration(entry, record);

        return record;
    });

5 Comments

Simple enough. Thanks
This does not work in .NET 6: MemoryCache's validation prevents zero or negative TimeSpans. It throws ArgumentOutOfRangeException: The relative expiration value must be positive.
@Anthony, maybe you're right, but the question was about code reuse, not about setting negative expiration value. The negative expiration is in question and I didn't change the logic, just extracted to separate method so it can be reused.
You can't re-use that code because you can't use it at all, directly or wrapped in a method. The question is about "prevent null items being added to cache" and what goes in the code that does that. AFAIK, it has to be a throw.
@Anthony, however I wanted to know if there w as better way to do this for all memory cache items instead of repeating the same code over and over - that's in question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.