Skip to content

Commit e5afc60

Browse files
committed
Use a factory method to create an instance of AsyncMemoryCache instead
1 parent a9320bc commit e5afc60

File tree

4 files changed

+45
-34
lines changed

4 files changed

+45
-34
lines changed

AsyncMemoryCache.Tests/AsyncMemoryCacheTests.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class AsyncMemoryCacheTests
1717
public async Task FactoryIsInvoked_DoesNotBlock()
1818
{
1919
var configuration = CreateConfiguration();
20-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(configuration);
20+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(configuration);
2121

2222
var semaphore = new SemaphoreSlim(0, 1);
2323

@@ -39,7 +39,7 @@ public async Task FactoryIsInvoked_DoesNotBlock()
3939
public async Task GetOrCreateObjectIsReturnedInCacheEntity()
4040
{
4141
var configuration = CreateConfiguration();
42-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(configuration);
42+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(configuration);
4343

4444
var objectToCache = Substitute.For<IAsyncDisposable>();
4545
var factory = () => Task.FromResult(objectToCache);
@@ -54,7 +54,7 @@ public async Task GetOrCreateObjectIsReturnedInCacheEntity()
5454
public async Task GetOrCreateObjectIsReturnedFromIndexer()
5555
{
5656
var configuration = CreateConfiguration();
57-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(configuration);
57+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(configuration);
5858

5959
var objectToCache = Substitute.For<IAsyncDisposable>();
6060
var factory = () => Task.FromResult(objectToCache);
@@ -70,7 +70,7 @@ public async Task GetOrCreateObjectIsReturnedFromIndexer()
7070
public void GetOrCreateCalledTwice_ReturnsPreviousCacheEntity()
7171
{
7272
var configuration = CreateConfiguration();
73-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(configuration);
73+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(configuration);
7474

7575
var factory = () => Task.FromResult(Substitute.For<IAsyncDisposable>());
7676

@@ -90,7 +90,7 @@ public void EvictionBehaviorIsStarted()
9090
EvictionBehavior = evictionBehavior
9191
};
9292

93-
_ = new AsyncMemoryCache<string, IAsyncDisposable>(config);
93+
_ = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
9494

9595
evictionBehavior
9696
.Received(1)
@@ -103,7 +103,7 @@ public void EvictionBehaviorIsStarted()
103103
public void ContainsKey()
104104
{
105105
var configuration = CreateConfiguration();
106-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(configuration);
106+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(configuration);
107107

108108
var factory = () => Task.FromResult(Substitute.For<IAsyncDisposable>());
109109

@@ -131,7 +131,7 @@ public async Task DisposeAsync()
131131
}
132132
};
133133

134-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
134+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
135135

136136
await target.DisposeAsync();
137137

@@ -153,7 +153,7 @@ public void NewCacheEntityReferenceReturnedOnEveryCall()
153153
CacheBackingStore = new Dictionary<string, CacheEntity<string, IAsyncDisposable>>()
154154
};
155155

156-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
156+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
157157

158158
const string key = "test";
159159
var cacheEntityReference1 = target.GetOrCreate(key, () => Task.FromResult(cacheObject));
@@ -183,7 +183,7 @@ public void NewCacheEntityIsCreatedIfUsesIsBelowZero()
183183
CacheBackingStore = new Dictionary<string, CacheEntity<string, IAsyncDisposable>>()
184184
};
185185

186-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
186+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
187187

188188
const string key = "test";
189189
var cacheEntityReference1 = target.GetOrCreate(key, () => Task.FromResult(cacheObject));
@@ -210,7 +210,7 @@ public void TryGetValue_ReturnsFalseIfItemDoesNotExist()
210210
CacheBackingStore = new Dictionary<string, CacheEntity<string, IAsyncDisposable>>()
211211
};
212212

213-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
213+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
214214

215215
var exists = target.TryGetValue("doesNotExist", out var cacheEntityReference);
216216

@@ -235,7 +235,7 @@ public void TryGetValue_ReturnsFalseWhenBeingDisposed()
235235

236236
config.CacheBackingStore[key].References = -1;
237237

238-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
238+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
239239

240240
var exists = target.TryGetValue(key, out var cacheEntityReference);
241241

@@ -259,7 +259,7 @@ public void TryGetValue_ReturnsTrueIfItemExistsAndIncrementsReferenceCount()
259259
}
260260
};
261261

262-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
262+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
263263

264264
var exists = target.TryGetValue(key, out var cacheEntityReference);
265265

@@ -287,7 +287,7 @@ public void TryGetValue_ExistingItemWithExpirationStrategy_CallsCacheEntityAcces
287287
}
288288
};
289289

290-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
290+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
291291

292292
_ = target.TryGetValue(key, out var cacheEntityReference);
293293

@@ -313,7 +313,7 @@ public void Indexer_ExistingItemWithExpirationStrategy_CallsCacheEntityAccessed(
313313
}
314314
};
315315

316-
var target = new AsyncMemoryCache<string, IAsyncDisposable>(config);
316+
var target = AsyncMemoryCache<string, IAsyncDisposable>.Create(config);
317317

318318
_ = target[key];
319319

AsyncMemoryCache/AsyncMemoryCache.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,7 @@ public sealed class AsyncMemoryCache<TKey, TValue> : IAsyncDisposable, IAsyncMem
7171
private readonly IDictionary<TKey, CacheEntity<TKey, TValue>> _cache;
7272
private readonly ILogger<AsyncMemoryCache<TKey, TValue>> _logger;
7373

74-
/// <summary>
75-
/// Creates a new instance of <see cref="AsyncMemoryCache{TKey, TValue}"/> with the supplied arguments.
76-
/// </summary>
77-
/// <param name="configuration">The <see cref="IAsyncMemoryCacheConfiguration{TKey, TValue}"/>.</param>
78-
/// <param name="logger">The optional <see cref="ILogger{CategoryName}">ILogger</see>&lt;<see cref="AsyncMemoryCache{TKey, TValue}"></see>&gt;</param>
79-
public AsyncMemoryCache(IAsyncMemoryCacheConfiguration<TKey, TValue> configuration, ILogger<AsyncMemoryCache<TKey, TValue>>? logger = null)
74+
private AsyncMemoryCache(IAsyncMemoryCacheConfiguration<TKey, TValue> configuration, ILogger<AsyncMemoryCache<TKey, TValue>>? logger = null)
8075
{
8176
#if NET8_0_OR_GREATER
8277
ArgumentNullException.ThrowIfNull(configuration);
@@ -89,7 +84,18 @@ public AsyncMemoryCache(IAsyncMemoryCacheConfiguration<TKey, TValue> configurati
8984
_cache = configuration.CacheBackingStore;
9085

9186
_logger = logger ?? NullLoggerFactory.Instance.CreateLogger<AsyncMemoryCache<TKey, TValue>>();
92-
configuration.EvictionBehavior.Start(configuration, _logger);
87+
}
88+
89+
/// <summary>
90+
/// Creates a new instance of <see cref="AsyncMemoryCache{TKey, TValue}"/> with the supplied arguments.
91+
/// </summary>
92+
/// <param name="configuration">The <see cref="IAsyncMemoryCacheConfiguration{TKey, TValue}"/>.</param>
93+
/// <param name="logger">The optional <see cref="ILogger{CategoryName}">ILogger</see>&lt;<see cref="AsyncMemoryCache{TKey, TValue}"></see>&gt;</param>
94+
public static AsyncMemoryCache<TKey, TValue> Create(IAsyncMemoryCacheConfiguration<TKey, TValue> configuration, ILogger<AsyncMemoryCache<TKey, TValue>>? logger = null)
95+
{
96+
var asyncMemoryCache = new AsyncMemoryCache<TKey, TValue>(configuration, logger);
97+
configuration.EvictionBehavior.Start(configuration, asyncMemoryCache._logger);
98+
return asyncMemoryCache;
9399
}
94100

95101
/// <inheritdoc/>

AsyncMemoryCache/Extensions/ServiceCollectionExtensions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Logging;
23
using System;
34

45
namespace AsyncMemoryCache.Extensions;
@@ -20,7 +21,10 @@ public static IServiceCollection AddAsyncMemoryCache<TKey, TValue>(this IService
2021
where TValue : IAsyncDisposable
2122
{
2223
return services
23-
.AddSingleton<IAsyncMemoryCache<TKey, TValue>, AsyncMemoryCache<TKey, TValue>>()
24+
.AddSingleton<IAsyncMemoryCache<TKey, TValue>>(
25+
sp => AsyncMemoryCache<TKey, TValue>.Create(
26+
sp.GetRequiredService<IAsyncMemoryCacheConfiguration<TKey, TValue>>(),
27+
sp.GetService<ILogger<AsyncMemoryCache<TKey, TValue>>>()))
2428
.AddSingleton<IAsyncMemoryCacheConfiguration<TKey, TValue>, AsyncMemoryCacheConfiguration<TKey, TValue>>();
2529
}
2630

@@ -37,7 +41,9 @@ public static IServiceCollection AddAsyncMemoryCache<TKey, TValue>(this IService
3741
where TValue : IAsyncDisposable
3842
{
3943
return services
40-
.AddSingleton<IAsyncMemoryCache<TKey, TValue>, AsyncMemoryCache<TKey, TValue>>()
41-
.AddSingleton(configuration);
44+
.AddSingleton<IAsyncMemoryCache<TKey, TValue>>(
45+
sp => AsyncMemoryCache<TKey, TValue>.Create(
46+
configuration,
47+
sp.GetService<ILogger<AsyncMemoryCache<TKey, TValue>>>()));
4248
}
4349
}

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
- Lazy construction of cache object
1616
- Supports asynchronous factories
1717
- Automatic disposal of expired cache entries
18-
- Integration with Microsoft.Extensions.DependencyInjection
19-
- Integration with Microsoft.Extensions.Logging
18+
- (Optional) Integration with Microsoft.Extensions.DependencyInjection
19+
- (Optional) Integration with Microsoft.Extensions.Logging
2020

2121

2222
### Usage
2323
```cs
2424
using AsyncMemoryCache;
25+
using AsyncMemoryCache.Extensions;
2526

2627
ILoggerFactory loggerFactory = ...;
2728

@@ -32,17 +33,16 @@ var cacheConfig = new AsyncMemoryCacheConfiguration<string, TheClassToCache>
3233
EvictionBehavior = EvictionBehavior.Default // new DefaultEvictionBehavior(TimeProvider.System, TimeSpan.FromSeconds(45))
3334
};
3435

35-
var cache = new AsyncMemoryCache<string, TheClassToCache>(cacheConfig, cacheLogger); // Logger is optional
36+
var cache = AsyncMemoryCache<string, TheClassToCache>.Create(cacheConfig, cacheLogger); // Logger is optional
3637
3738
// The factory is started here, will not block
3839
var cacheEntityReference = cache.GetOrCreate("theKey", async () =>
3940
{
4041
var createdObject = await ...;
4142
await Task.Delay(1000);
4243
return createdObject;
43-
});
44-
45-
cacheEntityReference.CacheEntity.WithSlidingExpiration(TimeSpan.FromHours(12));
44+
})
45+
.WithSlidingExpiration(TimeSpan.FromHours(12));
4646

4747
// Will block here until the object is created
4848
var theCachedObject = await cache["theKey"]; // Short-hand for await cache["theKey"].CacheEntity.ObjectFactory;
@@ -57,15 +57,14 @@ The way you deal with this is by `using` (calling `Dispose()` on) the `CacheEnti
5757
As long as at least one `CacheEntityReference` is alive (i.e. not disposed and still in-scope) the underlying cached object will not be evicted/disposed
5858

5959
```cs
60+
// Create a cache entry that expires in 15 seconds
6061
var cacheEntityReference = cache.GetOrCreate("theKey", async () =>
6162
{
6263
var createdObject = await ...;
6364
await Task.Delay(1000);
6465
return createdObject;
65-
});
66-
67-
// Object expires in 15 seconds
68-
cacheEntityReference.CacheEntity.WithAbsoluteExpiration(DateTimeOffset.UtcNow.AddSeconds(15));
66+
})
67+
.WithAbsoluteExpiration(DateTimeOffset.UtcNow.AddSeconds(15));
6968

7069
// do stuff with cache entry that takes longer than 15 seconds
7170

0 commit comments

Comments
 (0)