Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new IMemoryCache extensions #94335

Merged
merged 7 commits into from Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -61,7 +61,9 @@ public static partial class CacheExtensions
{
public static object? Get(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; }
public static System.Threading.Tasks.Task<TItem?> GetOrCreateAsync<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func<Microsoft.Extensions.Caching.Memory.ICacheEntry, System.Threading.Tasks.Task<TItem>> factory) { throw null; }
public static System.Threading.Tasks.Task<TItem?> GetOrCreateAsync<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func<Microsoft.Extensions.Caching.Memory.ICacheEntry, System.Threading.Tasks.Task<TItem>> factory, Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions? createOptions) { throw null; }
public static TItem? GetOrCreate<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func<Microsoft.Extensions.Caching.Memory.ICacheEntry, TItem> factory) { throw null; }
public static TItem? GetOrCreate<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, System.Func<Microsoft.Extensions.Caching.Memory.ICacheEntry, TItem> factory, Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions? createOptions) { throw null; }
public static TItem? Get<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key) { throw null; }
public static TItem Set<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value) { throw null; }
public static TItem Set<TItem>(this Microsoft.Extensions.Caching.Memory.IMemoryCache cache, object key, TItem value, Microsoft.Extensions.Caching.Memory.MemoryCacheEntryOptions? options) { throw null; }
Expand Down
Expand Up @@ -178,6 +178,33 @@ public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value,
return (TItem?)result;
}

/// <summary>
/// Gets the value associated with this key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.
/// </summary>
/// <typeparam name="TItem">The type of the object to get.</typeparam>
/// <param name="cache">The <see cref="IMemoryCache"/> instance this method extends.</param>
/// <param name="key">The key of the entry to look for or create.</param>
/// <param name="factory">The factory that creates the value associated with this key if the key does not exist in the cache.</param>
/// <param name="createOptions">The <see cref="MemoryCacheEntryOptions"/> needs to be applied to the created <see cref="ICacheEntry"/> if not null.</param>
WeihanLi marked this conversation as resolved.
Show resolved Hide resolved
/// <returns>The value associated with this key.</returns>
public static TItem? GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory, MemoryCacheEntryOptions? createOptions)
WeihanLi marked this conversation as resolved.
Show resolved Hide resolved
{
if (!cache.TryGetValue(key, out object? result))
{
using ICacheEntry entry = cache.CreateEntry(key);

if (createOptions != null)
{
entry.SetOptions(createOptions);
}

result = factory(entry);
entry.Value = result;
}

return (TItem?)result;
}

/// <summary>
/// Asynchronously gets the value associated with this key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.
/// </summary>
Expand All @@ -198,5 +225,32 @@ public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value,

return (TItem?)result;
}

/// <summary>
/// Asynchronously gets the value associated with this key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.
/// </summary>
/// <typeparam name="TItem">The type of the object to get.</typeparam>
/// <param name="cache">The <see cref="IMemoryCache"/> instance this method extends.</param>
/// <param name="key">The key of the entry to look for or create.</param>
/// <param name="factory">The factory task that creates the value associated with this key if the key does not exist in the cache.</param>
/// <param name="createOptions">The <see cref="MemoryCacheEntryOptions"/> needs to be applied to the created <see cref="ICacheEntry"/> if not null.</param>
WeihanLi marked this conversation as resolved.
Show resolved Hide resolved
/// <returns>The task object representing the asynchronous operation.</returns>
public static async Task<TItem?> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory, MemoryCacheEntryOptions? createOptions)
{
if (!cache.TryGetValue(key, out object? result))
{
using ICacheEntry entry = cache.CreateEntry(key);

if (createOptions != null)
{
entry.SetOptions(createOptions);
}

result = await factory(entry).ConfigureAwait(false);
WeihanLi marked this conversation as resolved.
Show resolved Hide resolved
entry.Value = result;
}

return (TItem?)result;
}
}
}
Expand Up @@ -793,6 +793,40 @@ public async Task GetOrCreateAsyncFromCacheWithNullKeyThrows()
var cache = CreateCache();
await Assert.ThrowsAsync<ArgumentNullException>(async () => await cache.GetOrCreateAsync<object>(null, null));
}

[Fact]
public void GetOrCreateWithCacheEntryOptions()
{
var cacheKey = "test";
var cache = CreateCache();
var expiry = 1000;
var cacheEntryOptions = new MemoryCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMilliseconds(expiry)
};
var value = cache.GetOrCreate<string>(cacheKey, _ => cacheKey, cacheEntryOptions);
Assert.Equal(cacheKey, value);
Assert.True(cache.TryGetValue(cacheKey, out _));
Thread.Sleep(expiry * 2);
WeihanLi marked this conversation as resolved.
Show resolved Hide resolved
Assert.False(cache.TryGetValue(cacheKey, out _));
}

[Fact]
public async Task GetOrCreateAsyncWithCacheEntryOptions()
{
var cacheKey = "test";
var cache = CreateCache();
var expiry = 1000;
var cacheEntryOptions = new MemoryCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMilliseconds(expiry)
};
var value = await cache.GetOrCreateAsync<string>(cacheKey, _ => Task.FromResult(cacheKey), cacheEntryOptions);
Assert.Equal(cacheKey, value);
Assert.True(cache.TryGetValue(cacheKey, out _));
await Task.Delay(expiry * 2);
Assert.False(cache.TryGetValue(cacheKey, out _));
}

private class TestKey
{
Expand Down