|
8 | 8 | using System.Threading.Tasks;
|
9 | 9 | using Microsoft.Extensions.Caching.Distributed;
|
10 | 10 | using Microsoft.Extensions.Caching.Hybrid;
|
| 11 | +using Microsoft.Extensions.Caching.Memory; |
11 | 12 | using Microsoft.Extensions.DependencyInjection;
|
12 | 13 | using Microsoft.Extensions.DependencyInjection.Extensions;
|
13 | 14 | using Microsoft.Extensions.Logging;
|
14 | 15 | using Microsoft.Extensions.Logging.Abstractions;
|
| 16 | +using Microsoft.Extensions.Options; |
15 | 17 | using Moq;
|
16 | 18 | using Xunit;
|
17 | 19 |
|
@@ -142,16 +144,46 @@ public void AddStackExchangeRedisCache_HybridCacheDetected(bool hybridCacheActiv
|
142 | 144 | services.AddStackExchangeRedisCache(options => { });
|
143 | 145 | if (hybridCacheActive)
|
144 | 146 | {
|
145 |
| - services.TryAddSingleton<HybridCache>(new DummyHybridCache()); |
| 147 | + services.AddMemoryCache(); |
| 148 | + services.TryAddSingleton<HybridCache, DummyHybridCache>(); |
146 | 149 | }
|
147 | 150 |
|
148 | 151 | using var provider = services.BuildServiceProvider();
|
149 | 152 | var cache = Assert.IsAssignableFrom<RedisCache>(provider.GetRequiredService<IDistributedCache>());
|
150 |
| - Assert.Equal(hybridCacheActive, cache.HybridCacheActive); |
| 153 | + Assert.Equal(hybridCacheActive, cache.IsHybridCacheActive()); |
151 | 154 | }
|
152 | 155 |
|
153 | 156 | sealed class DummyHybridCache : HybridCache
|
154 | 157 | {
|
| 158 | + // emulate the layout from HybridCache in dotnet/extensions |
| 159 | + public DummyHybridCache(IOptions<HybridCacheOptions> options, IServiceProvider services) |
| 160 | + { |
| 161 | + if (services is null) |
| 162 | + { |
| 163 | + throw new ArgumentNullException(nameof(services)); |
| 164 | + } |
| 165 | + |
| 166 | + var l1 = services.GetRequiredService<IMemoryCache>(); |
| 167 | + _ = options.Value; |
| 168 | + var logger = services.GetService<ILoggerFactory>()?.CreateLogger(typeof(HybridCache)) ?? NullLogger.Instance; |
| 169 | + // var clock = services.GetService<TimeProvider>() ?? TimeProvider.System; |
| 170 | + var l2 = services.GetService<IDistributedCache>(); // note optional |
| 171 | + |
| 172 | + // ignore L2 if it is really just the same L1, wrapped |
| 173 | + // (note not just an "is" test; if someone has a custom subclass, who knows what it does?) |
| 174 | + if (l2 is not null |
| 175 | + && l2.GetType() == typeof(MemoryDistributedCache) |
| 176 | + && l1.GetType() == typeof(MemoryCache)) |
| 177 | + { |
| 178 | + l2 = null; |
| 179 | + } |
| 180 | + |
| 181 | + IHybridCacheSerializerFactory[] factories = services.GetServices<IHybridCacheSerializerFactory>().ToArray(); |
| 182 | + Array.Reverse(factories); |
| 183 | + } |
| 184 | + |
| 185 | + public class HybridCacheOptions { } |
| 186 | + |
155 | 187 | public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> factory, HybridCacheEntryOptions options = null, IEnumerable<string> tags = null, CancellationToken cancellationToken = default)
|
156 | 188 | => throw new NotSupportedException();
|
157 | 189 |
|
|
0 commit comments