Skip to content

Commit e7ce050

Browse files
author
László Jakab
committed
Memory cache extensions
1 parent 280eba0 commit e7ce050

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
using Microsoft.Extensions.Caching.Memory;
2+
using Microsoft.Extensions.Primitives;
3+
4+
namespace AutSoft.Common.Caching;
5+
6+
/// <summary>
7+
/// Extension functions for <see cref="IMemoryCache"/>
8+
/// </summary>
9+
public static class MemoryCacheExtensions
10+
{
11+
private const string Postfix = "CancellationTokenSource";
12+
13+
/// <summary>
14+
/// Get or create a cached element with error handling
15+
/// </summary>
16+
/// <typeparam name="TItem">The type of the cached element</typeparam>
17+
/// <param name="cache">An <see cref="IMemoryCache"/> object</param>
18+
/// <param name="key">The key of the cached element</param>
19+
/// <param name="factory">The factory method, which can create the element if it isn't cached</param>
20+
/// <param name="options">Options of the caching</param>
21+
/// <returns>The finded or created element</returns>
22+
public static async Task<TItem> GetOrCreateWithErrorHandlingAsync<TItem>(
23+
this IMemoryCache cache,
24+
string key,
25+
Func<ICacheEntry, Task<TItem>> factory,
26+
MemoryCacheEntryOptions? options = null)
27+
{
28+
try
29+
{
30+
return await cache.GetOrCreateAsync(key, entry =>
31+
{
32+
entry.SetOptions(options);
33+
entry.AddExpirationToken(cache.CreateToken(key));
34+
return factory(entry);
35+
});
36+
}
37+
catch
38+
{
39+
cache.Remove(key);
40+
throw;
41+
}
42+
}
43+
44+
/// <summary>
45+
/// Create or override an element in the cache
46+
/// </summary>
47+
/// <typeparam name="TItem">The type of the cached element</typeparam>
48+
/// <param name="cache">An <see cref="IMemoryCache"/> object</param>
49+
/// <param name="key">The key of the cached element</param>
50+
/// <param name="value">The cached value</param>
51+
/// <param name="size">The size of the cached value</param>
52+
/// <param name="options">Options of the caching</param>
53+
public static void SetWithErrorHandling<TItem>(
54+
this IMemoryCache cache,
55+
string key,
56+
TItem value,
57+
int size,
58+
MemoryCacheEntryOptions? options = null)
59+
{
60+
try
61+
{
62+
using var entry = cache.CreateEntry(key);
63+
entry.Size = size;
64+
entry.SetOptions(options);
65+
entry.AddExpirationToken(cache.CreateToken(key));
66+
entry.Value = value;
67+
}
68+
catch
69+
{
70+
cache.Remove(key);
71+
throw;
72+
}
73+
}
74+
75+
private static void SetOptions(this ICacheEntry entry, MemoryCacheEntryOptions? options = null)
76+
{
77+
if (options == null)
78+
{
79+
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1);
80+
entry.SlidingExpiration = TimeSpan.FromMinutes(10);
81+
entry.Priority = CacheItemPriority.Normal;
82+
}
83+
else
84+
{
85+
entry.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow;
86+
entry.SlidingExpiration = options.SlidingExpiration;
87+
entry.Priority = options.Priority;
88+
}
89+
}
90+
91+
private static IChangeToken CreateToken(this IMemoryCache cache, string key)
92+
{
93+
var tokenSourceKey = key + Postfix;
94+
95+
var source = cache.Set(
96+
tokenSourceKey,
97+
new CancellationTokenSource(),
98+
new MemoryCacheEntryOptions { Size = 1 });
99+
100+
return new CancellationChangeToken(source.Token);
101+
}
102+
103+
/// <summary>
104+
/// Invalidate a cached element's value
105+
/// </summary>
106+
/// <param name="cache">An <see cref="IMemoryCache"/> object</param>
107+
/// <param name="key">The key of the cached element</param>
108+
/// <returns>The element invalidated successfully or not</returns>
109+
public static bool Invalidate(this IMemoryCache cache, string key)
110+
{
111+
var tokenSourceKey = key + Postfix;
112+
113+
if (!cache.TryGetValue(tokenSourceKey, out CancellationTokenSource source))
114+
return false;
115+
116+
source.Cancel();
117+
cache.Remove(tokenSourceKey);
118+
119+
return true;
120+
}
121+
}

0 commit comments

Comments
 (0)