diff --git a/CHANGELOG.md b/CHANGELOG.md index 37591e2..aa02bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ -# Polly.Caching.MemoryCache change log +# Polly.Caching.Memory change log + +## 3.0.0 +- Allow caching of `default(TResult)` +- Compatible with Polly >= v7 + +## 2.0.2 +- No functional changes +- Indicate compatibility with Polly < v7 ## 2.0.2 - No functional changes diff --git a/GitVersionConfig.yaml b/GitVersionConfig.yaml index 02d54e2..aade6b1 100644 --- a/GitVersionConfig.yaml +++ b/GitVersionConfig.yaml @@ -1 +1 @@ -next-version: 2.0.2 \ No newline at end of file +next-version: 3.0.0 \ No newline at end of file diff --git a/README.md b/README.md index 5559bb4..bf33b53 100644 --- a/README.md +++ b/README.md @@ -27,49 +27,47 @@ Polly.Caching.MemoryCache <v2.0 supports .NET4.0, .NET4.5 and .NetStandard 1. ## Versions and Dependencies -Polly.Caching.Memory >=v2.0.2 and <v3 requires: +Polly.Caching.Memory >=v3.0 requires: + ++ [Polly](https://nuget.org/packages/polly) >= v7.0.0. ++ [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) v2.0.2 or above (or v1.1.2, for NetStandard 1.3). + +Polly.Caching.Memory >=v2.0.1 and <v3 requires: + [Polly](https://nuget.org/packages/polly) >= v6.1.1 and <v7. + [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) v2.0.2 or above (or v1.1.2, for NetStandard 1.3). -Polly.Caching.Memory >= v2.0.1 requires: +Polly.Caching.Memory v2.0.0 requires: + [Polly](https://nuget.org/packages/polly) >= v6.0.1 and <=v6.1.0. + [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) v2.0.2 or above (or v1.1.2, for NetStandard 1.3). -Polly.Caching.MemoryCache <v1.* requires: +Polly.Caching.MemoryCache v1.* requires: + [Polly](https://nuget.org/packages/polly) >=v5.9.0 and <v6. + [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) v1.1.2, for NetStandard 1.3. # How to use the Polly.Caching.Memory plugin -```csharp -// (1a): Create a MemoryCacheProvider instance in the .NET Framework, using the Polly.Caching.Memory nuget package. -// (full namespaces and types only shown here for disambiguation) -Polly.Caching.Memory.MemoryCacheProvider memoryCacheProvider - = new Polly.Caching.Memory.MemoryCacheProvider(System.Runtime.Caching.MemoryCache.Default); +### Example: Direct creation of CachePolicy (no DI) -// Or (1b): Create a MemoryCacheProvider instance in .NET Core / .NET Standard. -// (full namespaces and types only shown here for disambiguation) -// NB Only if you want to create your own Microsoft.Extensions.Caching.Memory.MemoryCache instance: +```csharp +// This approach creates a CachePolicy directly, with its own Microsoft.Extensions.Caching.Memory.MemoryCache instance: Microsoft.Extensions.Caching.Memory.IMemoryCache memoryCache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions()); Polly.Caching.Memory.MemoryCacheProvider memoryCacheProvider = new Polly.Caching.Memory.MemoryCacheProvider(memoryCache); -// (2) Create a Polly cache policy using that Polly.Caching.Memory.MemoryCacheProvider instance. +// Create a Polly cache policy using that Polly.Caching.Memory.MemoryCacheProvider instance. var cachePolicy = Policy.Cache(memoryCacheProvider, TimeSpan.FromMinutes(5)); +``` +### Example: Configure CachePolicy via MemoryCacheProvider in StartUp, for DI +```csharp +// (We pass a whole PolicyRegistry by dependency injection rather than the individual policy, +// on the assumption the app will probably use multiple policies.) -// Or (1c): Configure by dependency injection within ASP.NET Core -// See https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory -// and https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services - -// (In this example we choose to pass a whole PolicyRegistry by dependency injection rather than the individual policy, on the assumption the webapp will probably use multiple policies across the app.) - -// For example: public class Startup { public void ConfigureServices(IServiceCollection services) @@ -77,10 +75,15 @@ public class Startup services.AddMemoryCache(); services.AddSingleton(); - services.AddSingleton, Polly.Registry.PolicyRegistry>((serviceProvider) => + services.AddSingleton, Polly.Registry.PolicyRegistry>((serviceProvider) => { PolicyRegistry registry = new PolicyRegistry(); - registry.Add("myCachePolicy", Policy.CacheAsync(serviceProvider.GetRequiredService().AsyncFor(), TimeSpan.FromMinutes(5))); + registry.Add("myCachePolicy", + Policy.CacheAsync( + serviceProvider + .GetRequiredService() + .AsyncFor(), + TimeSpan.FromMinutes(5))); return registry; }); @@ -88,9 +91,9 @@ public class Startup } } -// In a controller, inject the policyRegistry and retrieve the policy: +// At the point of use, inject the policyRegistry and retrieve the policy: // (magic string "myCachePolicy" only hard-coded here to keep the example simple) -public MyController(IPolicyRegistry policyRegistry) +public MyController(IReadOnlyPolicyRegistry policyRegistry) { var _cachePolicy = policyRegistry.Get>("myCachePolicy"); // ... @@ -117,6 +120,7 @@ For details of changes by release see the [change log](CHANGELOG.md). * [@seanfarrow](https://github.com/seanfarrow) and [@reisenberger](https://github.com/reisenberger) - Initial caching architecture in the main Polly repo * [@kesmy](https://github.com/kesmy) - original structuring of the build for msbuild15, in the main Polly repo * [@seanfarrow](https://github.com/seanfarrow) - v2.0 update to Signed packages only to correspond with Polly v6.0.1 +* [@reisenberger](https://github.com/reisenberger) - Update to Polly v7.0.0 # Instructions for Contributing diff --git a/src/Polly.Caching.Memory.NetStandard13.Specs/Polly.Caching.Memory.NetStandard13.Specs.csproj b/src/Polly.Caching.Memory.NetStandard13.Specs/Polly.Caching.Memory.NetStandard13.Specs.csproj index fd59df7..8724a29 100644 --- a/src/Polly.Caching.Memory.NetStandard13.Specs/Polly.Caching.Memory.NetStandard13.Specs.csproj +++ b/src/Polly.Caching.Memory.NetStandard13.Specs/Polly.Caching.Memory.NetStandard13.Specs.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Polly.Caching.Memory.NetStandard13/Polly.Caching.Memory.NetStandard13.csproj b/src/Polly.Caching.Memory.NetStandard13/Polly.Caching.Memory.NetStandard13.csproj index be7b76c..a2f1b20 100644 --- a/src/Polly.Caching.Memory.NetStandard13/Polly.Caching.Memory.NetStandard13.csproj +++ b/src/Polly.Caching.Memory.NetStandard13/Polly.Caching.Memory.NetStandard13.csproj @@ -29,7 +29,8 @@ - + + \ No newline at end of file diff --git a/src/Polly.Caching.Memory.NetStandard13/Properties/AssemblyInfo.cs b/src/Polly.Caching.Memory.NetStandard13/Properties/AssemblyInfo.cs index 771f2b5..0ee7592 100644 --- a/src/Polly.Caching.Memory.NetStandard13/Properties/AssemblyInfo.cs +++ b/src/Polly.Caching.Memory.NetStandard13/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Polly.Caching.Memory")] -[assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.0.2.0")] -[assembly: AssemblyInformationalVersion("2.0.2.0")] +[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyFileVersion("3.0.0.0")] +[assembly: AssemblyInformationalVersion("3.0.0.0")] [assembly: CLSCompliant(false)] // Because Microsoft.Extensions.Caching.Memory.MemoryCache, on which Polly.Caching.MemoryCache.NetStandard13 depends, is not CLSCompliant. [assembly: InternalsVisibleTo("Polly.Caching.Memory.NetStandard13.Specs")] \ No newline at end of file diff --git a/src/Polly.Caching.Memory.NetStandard20/Polly.Caching.Memory.NetStandard20.csproj b/src/Polly.Caching.Memory.NetStandard20/Polly.Caching.Memory.NetStandard20.csproj index a1b21a0..97e7b4d 100644 --- a/src/Polly.Caching.Memory.NetStandard20/Polly.Caching.Memory.NetStandard20.csproj +++ b/src/Polly.Caching.Memory.NetStandard20/Polly.Caching.Memory.NetStandard20.csproj @@ -29,7 +29,7 @@ - + \ No newline at end of file diff --git a/src/Polly.Caching.Memory.NetStandard20/Properties/AssemblyInfo.cs b/src/Polly.Caching.Memory.NetStandard20/Properties/AssemblyInfo.cs index a8bea94..bc45d49 100644 --- a/src/Polly.Caching.Memory.NetStandard20/Properties/AssemblyInfo.cs +++ b/src/Polly.Caching.Memory.NetStandard20/Properties/AssemblyInfo.cs @@ -3,9 +3,9 @@ using System.Runtime.CompilerServices; [assembly: AssemblyTitle("Polly.Caching.Memory")] -[assembly: AssemblyVersion("2.0.0.0")] -[assembly: AssemblyFileVersion("2.0.2.0")] -[assembly: AssemblyInformationalVersion("2.0.2.0")] +[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyFileVersion("3.0.0.0")] +[assembly: AssemblyInformationalVersion("3.0.0.0")] [assembly: CLSCompliant(false)] // Because Microsoft.Extensions.Caching.Memory.MemoryCache, on which Polly.Caching.MemoryCache.NetStandard13 depends, is not CLSCompliant. [assembly: InternalsVisibleTo("Polly.Caching.Memory.NetStandard20.Specs")] \ No newline at end of file diff --git a/src/Polly.Caching.Memory.Shared/MemoryCacheProvider.cs b/src/Polly.Caching.Memory.Shared/MemoryCacheProvider.cs index 5f4d400..0ced952 100644 --- a/src/Polly.Caching.Memory.Shared/MemoryCacheProvider.cs +++ b/src/Polly.Caching.Memory.Shared/MemoryCacheProvider.cs @@ -19,25 +19,23 @@ public class MemoryCacheProvider : ISyncCacheProvider, IAsyncCacheProvider /// The memory cache instance in which to store cached items. public MemoryCacheProvider(IMemoryCache memoryCache) { - if (memoryCache == null) throw new ArgumentNullException(nameof(memoryCache)); - _cache = memoryCache; + _cache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache)); } /// /// Gets a value from cache. /// /// The cache key. - /// The value from cache; or null, if none was found. - public object Get(String key) + /// + /// A tuple whose first element is a value indicating whether the key was found in the cache, + /// and whose second element is the value from the cache (null if not found). + /// + public (bool, object) TryGet(string key) { - object value; - if (_cache.TryGetValue(key, out value)) - { - return value; - } - return null; + bool cacheHit = _cache.TryGetValue(key, out var value); + return (cacheHit, value); } - + /// /// Puts the specified value in the cache. /// @@ -59,7 +57,7 @@ public void Put(string key, object value, Ttl ttl) { options.AbsoluteExpiration = DateTimeOffset.MaxValue; } -else + else { options.AbsoluteExpirationRelativeToNow = ttl.Timespan < remaining ? ttl.Timespan : remaining; } @@ -69,17 +67,20 @@ public void Put(string key, object value, Ttl ttl) } /// - /// Gets a value from the memory cache as part of an asynchronous execution. The implementation is synchronous as there is no advantage to an asynchronous implementation for an in-memory cache. + /// Gets a value from the cache asynchronously. + /// The implementation is synchronous as there is no advantage to an asynchronous implementation for an in-memory cache. /// /// The cache key. - /// The cancellation token. - /// Whether async calls should continue on a captured synchronization context. For , this parameter is irrelevant and is ignored, as the implementation is synchronous. - /// A promising as Result the value from cache; or null, if none was found. - public Task GetAsync(string key, CancellationToken cancellationToken, bool continueOnCapturedContext) + /// The cancellation token. + /// Whether async calls should continue on a captured synchronization context. Note: if the underlying cache's async API does not support controlling whether to continue on a captured context, async Policy executions with continueOnCapturedContext == true cannot be guaranteed to remain on the captured context. + /// + /// A promising as Result a tuple whose first element is a value indicating whether + /// the key was found in the cache, and whose second element is the value from the cache (null if not found). + /// + public Task<(bool, object)> TryGetAsync(string key, CancellationToken cancellationToken, bool continueOnCapturedContext) { cancellationToken.ThrowIfCancellationRequested(); - return Task.FromResult(Get(key)); - // (With C#7.0, a ValueTask<> approach would be preferred, but some of our tfms do not support that. TO DO: Implement it, with preprocessor if/endif directives, for NetStandard) + return Task.FromResult(TryGet(key)); } /// @@ -97,7 +98,6 @@ public Task PutAsync(string key, object value, Ttl ttl, CancellationToken cancel cancellationToken.ThrowIfCancellationRequested(); Put(key, value, ttl); return Task.CompletedTask; - // (With C#7.0, a ValueTask<> approach would be preferred, but some of our tfms do not support that. TO DO: Implement it, with preprocessor if/endif directives, for NetStandard) } } } diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsBase.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsBase.cs new file mode 100644 index 0000000..2914c1c --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsBase.cs @@ -0,0 +1,131 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Polly.Caching.Memory.Specs.Integration +{ + public abstract class CacheRoundTripSpecsBase + { + protected CacheRoundTripSpecsBase(ICachePolicyFactory cachePolicyFactory) + { + CachePolicyFactory = cachePolicyFactory; + } + + protected ICachePolicyFactory CachePolicyFactory { get; } + + protected const string OperationKey = "SomeOperationKey"; + + public abstract Task Should_roundtrip_this_variant_of(TResult testValue); + + [Theory] + [MemberData(nameof(SampleClassData))] + public async Task Should_roundtrip_all_variants_of_reference_type(SampleClass testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + [Theory] + [MemberData(nameof(SampleStringData))] + public async Task Should_roundtrip_all_variants_of_string(String testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + [Theory] + [MemberData(nameof(SampleNumericData))] + public async Task Should_roundtrip_all_variants_of_numeric(int testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + [Theory] + [MemberData(nameof(SampleEnumData))] + public async Task Should_roundtrip_all_variants_of_enum(SampleEnum testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + [Theory] + [MemberData(nameof(SampleBoolData))] + public async Task Should_roundtrip_all_variants_of_bool(bool testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + [Theory] + [MemberData(nameof(SampleNullableBoolData))] + public async Task Should_roundtrip_all_variants_of_nullable_bool(bool? testValue) + { + await Should_roundtrip_this_variant_of(testValue); + } + + public static TheoryData SampleClassData => + new TheoryData + { + new SampleClass(), + new SampleClass() + { + StringProperty = "", + IntProperty = 1 + }, + (SampleClass)null, + default(SampleClass) + }; + + public static TheoryData SampleStringData => + new TheoryData + { + "some string", + "", + null, + default(string), + "null" + }; + + public static TheoryData SampleNumericData => + new TheoryData + { + -1, + 0, + 1, + default(int) + }; + + public static TheoryData SampleEnumData => + new TheoryData + { + SampleEnum.FirstValue, + SampleEnum.SecondValue, + default(SampleEnum), + }; + + public static TheoryData SampleBoolData => + new TheoryData + { + true, + false, + default(bool), + }; + + public static TheoryData SampleNullableBoolData => + new TheoryData + { + true, + false, + null, + default(bool?), + }; + + public class SampleClass + { + public string StringProperty { get; set; } + public int IntProperty { get; set; } + } + + public enum SampleEnum + { + FirstValue, + SecondValue, + } + } +} diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsSyncBase.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsSyncBase.cs new file mode 100644 index 0000000..5a13364 --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecsSyncBase.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; +using FluentAssertions; + +namespace Polly.Caching.Memory.Specs.Integration +{ + public abstract class CacheRoundTripSpecsSyncBase : CacheRoundTripSpecsBase + { + protected CacheRoundTripSpecsSyncBase(ICachePolicyFactory cachePolicyFactory) : base(cachePolicyFactory) + { + } + + public override Task Should_roundtrip_this_variant_of(TResult testValue) + { + // Arrange + var (cacheProvider, cache) = CachePolicyFactory.CreateSyncCachePolicy(); + + // Assert - should not be in cache + (bool cacheHit1, TResult fromCache1) = cacheProvider.TryGet(OperationKey); + cacheHit1.Should().BeFalse(); + fromCache1.Should().Be(default(TResult)); + + // Act - should execute underlying delegate and place in cache + int underlyingDelegateExecuteCount = 0; + cache.Execute(ctx => + { + underlyingDelegateExecuteCount++; + return testValue; + }, new Context(OperationKey)) + .ShouldBeEquivalentTo(testValue); + + // Assert - should have executed underlying delegate + underlyingDelegateExecuteCount.Should().Be(1); + + // Assert - should be in cache + (bool cacheHit2, TResult fromCache2) = cacheProvider.TryGet(OperationKey); + cacheHit2.Should().BeTrue(); + fromCache2.ShouldBeEquivalentTo(testValue); + + // Act - should execute underlying delegate and place in cache + cache.Execute(ctx => + { + underlyingDelegateExecuteCount++; + throw new Exception("Cache should be used so this should not get invoked."); + }, new Context(OperationKey)) + .ShouldBeEquivalentTo(testValue); + underlyingDelegateExecuteCount.Should().Be(1); + + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Async.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Async.cs new file mode 100644 index 0000000..34cf1db --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Async.cs @@ -0,0 +1,8 @@ +namespace Polly.Caching.Memory.Specs.Integration +{ + public class CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Async : CacheRoundTripSpecsAsyncBase { + public CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Async() : base(new MemoryCachePolicyFactory()) + { + } + } +} \ No newline at end of file diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Sync.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Sync.cs new file mode 100644 index 0000000..4b83ec0 --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Sync.cs @@ -0,0 +1,8 @@ +namespace Polly.Caching.Memory.Specs.Integration +{ + public class CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Sync : CacheRoundTripSpecsSyncBase { + public CacheRoundTripSpecs_NetStandardMemoryCacheProvider_Sync() : base(new MemoryCachePolicyFactory()) + { + } + } +} \ No newline at end of file diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripspecsAsyncBase.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripspecsAsyncBase.cs new file mode 100644 index 0000000..3bbd2e6 --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/CacheRoundTripspecsAsyncBase.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; + +namespace Polly.Caching.Memory.Specs.Integration +{ + public abstract class CacheRoundTripSpecsAsyncBase : CacheRoundTripSpecsBase + { + protected CacheRoundTripSpecsAsyncBase(ICachePolicyFactory cachePolicyFactory) : base(cachePolicyFactory) + { + } + + public override async Task Should_roundtrip_this_variant_of(TResult testValue) + { + // Arrange + var (cacheProvider, cache) = CachePolicyFactory.CreateAsyncCachePolicy(); + + // Assert - should not be in cache + (bool cacheHit1, TResult fromCache1) = await cacheProvider.TryGetAsync(OperationKey, CancellationToken.None, false); + cacheHit1.Should().BeFalse(); + fromCache1.Should().Be(default(TResult)); + + // Act - should execute underlying delegate and place in cache + int underlyingDelegateExecuteCount = 0; + (await cache.ExecuteAsync(ctx => + { + underlyingDelegateExecuteCount++; + return Task.FromResult(testValue); + }, new Context(OperationKey))) + .ShouldBeEquivalentTo(testValue); + + // Assert - should have executed underlying delegate + underlyingDelegateExecuteCount.Should().Be(1); + + // Assert - should be in cache + (bool cacheHit2, TResult fromCache2) = await cacheProvider.TryGetAsync(OperationKey, CancellationToken.None, false); + cacheHit2.Should().BeTrue(); + fromCache2.ShouldBeEquivalentTo(testValue); + + // Act - should execute underlying delegate and place in cache + (await cache.ExecuteAsync(ctx => + { + underlyingDelegateExecuteCount++; + throw new Exception("Cache should be used so this should not get invoked."); + }, new Context(OperationKey))) + .ShouldBeEquivalentTo(testValue); + underlyingDelegateExecuteCount.Should().Be(1); + } + } +} \ No newline at end of file diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/ICachePolicyFactory.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/ICachePolicyFactory.cs new file mode 100644 index 0000000..1020f3a --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/ICachePolicyFactory.cs @@ -0,0 +1,8 @@ +namespace Polly.Caching.Memory.Specs.Integration +{ + public interface ICachePolicyFactory + { + (ISyncCacheProvider, ISyncPolicy) CreateSyncCachePolicy(); + (IAsyncCacheProvider, IAsyncPolicy) CreateAsyncCachePolicy(); + } +} diff --git a/src/Polly.Caching.Memory.SharedSpecs/Integration/MemoryCachePolicyFactory.cs b/src/Polly.Caching.Memory.SharedSpecs/Integration/MemoryCachePolicyFactory.cs new file mode 100644 index 0000000..4bae172 --- /dev/null +++ b/src/Polly.Caching.Memory.SharedSpecs/Integration/MemoryCachePolicyFactory.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.Extensions.Caching.Memory; + +namespace Polly.Caching.Memory.Specs.Integration +{ + public class MemoryCachePolicyFactory : ICachePolicyFactory + { + public (ISyncCacheProvider, ISyncPolicy) CreateSyncCachePolicy() + { + IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()); + ISyncCacheProvider provider = new MemoryCacheProvider(memoryCache).For(); + + var policy = Policy.Cache(provider, TimeSpan.FromHours(1)); + return (provider, policy); + } + + public (IAsyncCacheProvider, IAsyncPolicy) CreateAsyncCachePolicy() + { + IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()); + IAsyncCacheProvider provider = new MemoryCacheProvider(memoryCache).AsyncFor(); + + var policy = Policy.CacheAsync(provider, TimeSpan.FromHours(1)); + return (provider, policy); + } + } +} diff --git a/src/Polly.Caching.Memory.SharedSpecs/Polly.Caching.Memory.SharedSpecs.projitems b/src/Polly.Caching.Memory.SharedSpecs/Polly.Caching.Memory.SharedSpecs.projitems index e3271db..5f69bab 100644 --- a/src/Polly.Caching.Memory.SharedSpecs/Polly.Caching.Memory.SharedSpecs.projitems +++ b/src/Polly.Caching.Memory.SharedSpecs/Polly.Caching.Memory.SharedSpecs.projitems @@ -9,6 +9,13 @@ Polly.Caching.Memory.Specs - + + + + + + + + \ No newline at end of file diff --git a/src/Polly.Caching.Memory.SharedSpecs/MemoryCacheProviderSpecs.cs b/src/Polly.Caching.Memory.SharedSpecs/Unit/MemoryCacheProviderSpecs.cs similarity index 93% rename from src/Polly.Caching.Memory.SharedSpecs/MemoryCacheProviderSpecs.cs rename to src/Polly.Caching.Memory.SharedSpecs/Unit/MemoryCacheProviderSpecs.cs index 2b6c2fd..f8d0c17 100644 --- a/src/Polly.Caching.Memory.SharedSpecs/MemoryCacheProviderSpecs.cs +++ b/src/Polly.Caching.Memory.SharedSpecs/Unit/MemoryCacheProviderSpecs.cs @@ -6,7 +6,7 @@ using Polly.Caching.Memory; using Microsoft.Extensions.Caching.Memory; -namespace Polly.Specs.Caching.Memory +namespace Polly.Specs.Caching.Memory.Unit { public class MemoryCacheProviderSpecs { @@ -42,28 +42,26 @@ public void Get_should_return_instance_previously_stored_in_cache() string key = Guid.NewGuid().ToString(); object value = new object(); -#if PORTABLE - using (Microsoft.Extensions.Caching.Memory.ICacheEntry entry = memoryCache.CreateEntry(key)) { + using (ICacheEntry entry = memoryCache.CreateEntry(key)) { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10); entry.Value = value; } -#else - memoryCache[key] = value; -#endif MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache); - object got = provider.Get(key); - got.Should().BeSameAs(value); + (bool cacheHit, object payload) = provider.TryGet(key); + cacheHit.Should().BeTrue(); + payload.Should().BeSameAs(value); } [Fact] - public void Get_should_return_null_on_unknown_key() + public void Get_should_return_false_on_unknown_key() { IMemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions()); MemoryCacheProvider provider = new MemoryCacheProvider(memoryCache); - object got = provider.Get(Guid.NewGuid().ToString()); - got.Should().BeNull(); + (bool cacheHit, object payload) = provider.TryGet(Guid.NewGuid().ToString()); + cacheHit.Should().BeFalse(); + payload.Should().BeNull(); } #endregion diff --git a/src/Polly.Caching.Memory.nuspec b/src/Polly.Caching.Memory.nuspec index 8f3268c..09c1554 100644 --- a/src/Polly.Caching.Memory.nuspec +++ b/src/Polly.Caching.Memory.nuspec @@ -13,6 +13,11 @@ Polly Cache Caching Cache-aside Copyright © 2019, App vNext + 3.0.0 + --------------------- + - Allow caching of default(TResult) + - Compatible with Polly >= v7 + 2.0.2 --------------------- - No functional changes @@ -53,11 +58,12 @@ - + + - +