Skip to content

Commit a7d6abf

Browse files
authored
Merge pull request #33 from reisenberger/v300
Version 3.0.0: For compatibility with (forthcoming) Polly v7.0.0
2 parents 84bbf5b + 46edf31 commit a7d6abf

19 files changed

+376
-67
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
# Polly.Caching.MemoryCache change log
1+
# Polly.Caching.Memory change log
2+
3+
## 3.0.0
4+
- Allow caching of `default(TResult)`
5+
- Compatible with Polly >= v7
6+
7+
## 2.0.2
8+
- No functional changes
9+
- Indicate compatibility with Polly < v7
210

311
## 2.0.2
412
- No functional changes

GitVersionConfig.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
next-version: 2.0.2
1+
next-version: 3.0.0

README.md

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,70 +27,73 @@ Polly.Caching.MemoryCache <v2.0 supports .NET4.0, .NET4.5 and .NetStandard 1.
2727

2828
## Versions and Dependencies
2929

30-
Polly.Caching.Memory >=v2.0.2 and <v3 requires:
30+
Polly.Caching.Memory >=v3.0 requires:
31+
32+
+ [Polly](https://nuget.org/packages/polly) >= v7.0.0.
33+
+ [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).
34+
35+
Polly.Caching.Memory >=v2.0.1 and <v3 requires:
3136

3237
+ [Polly](https://nuget.org/packages/polly) >= v6.1.1 and <v7.
3338
+ [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).
3439

35-
Polly.Caching.Memory >= v2.0.1 requires:
40+
Polly.Caching.Memory v2.0.0 requires:
3641

3742
+ [Polly](https://nuget.org/packages/polly) >= v6.0.1 and <=v6.1.0.
3843
+ [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).
3944

40-
Polly.Caching.MemoryCache <v1.* requires:
45+
Polly.Caching.MemoryCache v1.* requires:
4146

4247
+ [Polly](https://nuget.org/packages/polly) >=v5.9.0 and <v6.
4348
+ [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) v1.1.2, for NetStandard 1.3.
4449

4550
# How to use the Polly.Caching.Memory plugin
4651

47-
```csharp
48-
// (1a): Create a MemoryCacheProvider instance in the .NET Framework, using the Polly.Caching.Memory nuget package.
49-
// (full namespaces and types only shown here for disambiguation)
50-
Polly.Caching.Memory.MemoryCacheProvider memoryCacheProvider
51-
= new Polly.Caching.Memory.MemoryCacheProvider(System.Runtime.Caching.MemoryCache.Default);
52+
### Example: Direct creation of CachePolicy (no DI)
5253

53-
// Or (1b): Create a MemoryCacheProvider instance in .NET Core / .NET Standard.
54-
// (full namespaces and types only shown here for disambiguation)
55-
// NB Only if you want to create your own Microsoft.Extensions.Caching.Memory.MemoryCache instance:
54+
```csharp
55+
// This approach creates a CachePolicy directly, with its own Microsoft.Extensions.Caching.Memory.MemoryCache instance:
5656
Microsoft.Extensions.Caching.Memory.IMemoryCache memoryCache
5757
= new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());
5858
Polly.Caching.Memory.MemoryCacheProvider memoryCacheProvider
5959
= new Polly.Caching.Memory.MemoryCacheProvider(memoryCache);
6060

61-
// (2) Create a Polly cache policy using that Polly.Caching.Memory.MemoryCacheProvider instance.
61+
// Create a Polly cache policy using that Polly.Caching.Memory.MemoryCacheProvider instance.
6262
var cachePolicy = Policy.Cache(memoryCacheProvider, TimeSpan.FromMinutes(5));
63+
```
6364

65+
### Example: Configure CachePolicy via MemoryCacheProvider in StartUp, for DI
6466

67+
```csharp
68+
// (We pass a whole PolicyRegistry by dependency injection rather than the individual policy,
69+
// on the assumption the app will probably use multiple policies.)
6570
66-
// Or (1c): Configure by dependency injection within ASP.NET Core
67-
// See https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory
68-
// and https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services
69-
70-
// (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.)
71-
72-
// For example:
7371
public class Startup
7472
{
7573
public void ConfigureServices(IServiceCollection services)
7674
{
7775
services.AddMemoryCache();
7876
services.AddSingleton<Polly.Caching.IAsyncCacheProvider, Polly.Caching.Memory.MemoryCacheProvider>();
7977

80-
services.AddSingleton<Polly.Registry.IPolicyRegistry<string>, Polly.Registry.PolicyRegistry>((serviceProvider) =>
78+
services.AddSingleton<Polly.Registry.IReadOnlyPolicyRegistry<string>, Polly.Registry.PolicyRegistry>((serviceProvider) =>
8179
{
8280
PolicyRegistry registry = new PolicyRegistry();
83-
registry.Add("myCachePolicy", Policy.CacheAsync<HttpResponseMessage>(serviceProvider.GetRequiredService<IAsyncCacheProvider>().AsyncFor<HttpResponseMessage>(), TimeSpan.FromMinutes(5)));
81+
registry.Add("myCachePolicy",
82+
Policy.CacheAsync<HttpResponseMessage>(
83+
serviceProvider
84+
.GetRequiredService<IAsyncCacheProvider>()
85+
.AsyncFor<HttpResponseMessage>(),
86+
TimeSpan.FromMinutes(5)));
8487
return registry;
8588
});
8689

8790
// ...
8891
}
8992
}
9093

91-
// In a controller, inject the policyRegistry and retrieve the policy:
94+
// At the point of use, inject the policyRegistry and retrieve the policy:
9295
// (magic string "myCachePolicy" only hard-coded here to keep the example simple)
93-
public MyController(IPolicyRegistry<string> policyRegistry)
96+
public MyController(IReadOnlyPolicyRegistry<string> policyRegistry)
9497
{
9598
var _cachePolicy = policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>("myCachePolicy");
9699
// ...
@@ -117,6 +120,7 @@ For details of changes by release see the [change log](CHANGELOG.md).
117120
* [@seanfarrow](https://github.com/seanfarrow) and [@reisenberger](https://github.com/reisenberger) - Initial caching architecture in the main Polly repo
118121
* [@kesmy](https://github.com/kesmy) - original structuring of the build for msbuild15, in the main Polly repo
119122
* [@seanfarrow](https://github.com/seanfarrow) - v2.0 update to Signed packages only to correspond with Polly v6.0.1
123+
* [@reisenberger](https://github.com/reisenberger) - Update to Polly v7.0.0
120124

121125

122126
# Instructions for Contributing

src/Polly.Caching.Memory.NetStandard13.Specs/Polly.Caching.Memory.NetStandard13.Specs.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<ItemGroup>
1818
<PackageReference Include="FluentAssertions" Version="4.19.3" />
1919
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
20+
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
2021
<PackageReference Include="xunit" Version="2.2.0" />
2122
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
2223

src/Polly.Caching.Memory.NetStandard13/Polly.Caching.Memory.NetStandard13.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
</ItemGroup>
3030
<ItemGroup>
3131
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="1.1.2" />
32-
<PackageReference Include="Polly" Version="6.1.1" />
32+
<PackageReference Include="Polly" Version="7.0.0" />
33+
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
3334
</ItemGroup>
3435
<Import Project="..\Polly.Caching.Memory.Shared\Polly.Caching.Memory.Shared.projitems" Label="Shared" />
3536
</Project>

src/Polly.Caching.Memory.NetStandard13/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
using System.Runtime.CompilerServices;
44

55
[assembly: AssemblyTitle("Polly.Caching.Memory")]
6-
[assembly: AssemblyVersion("2.0.0.0")]
7-
[assembly: AssemblyFileVersion("2.0.2.0")]
8-
[assembly: AssemblyInformationalVersion("2.0.2.0")]
6+
[assembly: AssemblyVersion("3.0.0.0")]
7+
[assembly: AssemblyFileVersion("3.0.0.0")]
8+
[assembly: AssemblyInformationalVersion("3.0.0.0")]
99
[assembly: CLSCompliant(false)] // Because Microsoft.Extensions.Caching.Memory.MemoryCache, on which Polly.Caching.MemoryCache.NetStandard13 depends, is not CLSCompliant.
1010

1111
[assembly: InternalsVisibleTo("Polly.Caching.Memory.NetStandard13.Specs")]

src/Polly.Caching.Memory.NetStandard20/Polly.Caching.Memory.NetStandard20.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
</ItemGroup>
3030
<ItemGroup>
3131
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.2" />
32-
<PackageReference Include="Polly" Version="6.1.1" />
32+
<PackageReference Include="Polly" Version="7.0.0" />
3333
</ItemGroup>
3434
<Import Project="..\Polly.Caching.Memory.Shared\Polly.Caching.Memory.Shared.projitems" Label="Shared" />
3535
</Project>

src/Polly.Caching.Memory.NetStandard20/Properties/AssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
using System.Runtime.CompilerServices;
44

55
[assembly: AssemblyTitle("Polly.Caching.Memory")]
6-
[assembly: AssemblyVersion("2.0.0.0")]
7-
[assembly: AssemblyFileVersion("2.0.2.0")]
8-
[assembly: AssemblyInformationalVersion("2.0.2.0")]
6+
[assembly: AssemblyVersion("3.0.0.0")]
7+
[assembly: AssemblyFileVersion("3.0.0.0")]
8+
[assembly: AssemblyInformationalVersion("3.0.0.0")]
99
[assembly: CLSCompliant(false)] // Because Microsoft.Extensions.Caching.Memory.MemoryCache, on which Polly.Caching.MemoryCache.NetStandard13 depends, is not CLSCompliant.
1010

1111
[assembly: InternalsVisibleTo("Polly.Caching.Memory.NetStandard20.Specs")]

src/Polly.Caching.Memory.Shared/MemoryCacheProvider.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,23 @@ public class MemoryCacheProvider : ISyncCacheProvider, IAsyncCacheProvider
1919
/// <param name="memoryCache">The memory cache instance in which to store cached items.</param>
2020
public MemoryCacheProvider(IMemoryCache memoryCache)
2121
{
22-
if (memoryCache == null) throw new ArgumentNullException(nameof(memoryCache));
23-
_cache = memoryCache;
22+
_cache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
2423
}
2524

2625
/// <summary>
2726
/// Gets a value from cache.
2827
/// </summary>
2928
/// <param name="key">The cache key.</param>
30-
/// <returns>The value from cache; or null, if none was found.</returns>
31-
public object Get(String key)
29+
/// <returns>
30+
/// A tuple whose first element is a value indicating whether the key was found in the cache,
31+
/// and whose second element is the value from the cache (null if not found).
32+
/// </returns>
33+
public (bool, object) TryGet(string key)
3234
{
33-
object value;
34-
if (_cache.TryGetValue(key, out value))
35-
{
36-
return value;
37-
}
38-
return null;
35+
bool cacheHit = _cache.TryGetValue(key, out var value);
36+
return (cacheHit, value);
3937
}
40-
38+
4139
/// <summary>
4240
/// Puts the specified value in the cache.
4341
/// </summary>
@@ -59,7 +57,7 @@ public void Put(string key, object value, Ttl ttl)
5957
{
6058
options.AbsoluteExpiration = DateTimeOffset.MaxValue;
6159
}
62-
else
60+
else
6361
{
6462
options.AbsoluteExpirationRelativeToNow = ttl.Timespan < remaining ? ttl.Timespan : remaining;
6563
}
@@ -69,17 +67,20 @@ public void Put(string key, object value, Ttl ttl)
6967
}
7068

7169
/// <summary>
72-
/// Gets a value from the memory cache as part of an asynchronous execution. <para><remarks>The implementation is synchronous as there is no advantage to an asynchronous implementation for an in-memory cache.</remarks></para>
70+
/// Gets a value from the cache asynchronously.
71+
/// <para><remarks>The implementation is synchronous as there is no advantage to an asynchronous implementation for an in-memory cache.</remarks></para>
7372
/// </summary>
7473
/// <param name="key">The cache key.</param>
75-
/// <param name="cancellationToken">The cancellation token. </param>
76-
/// <param name="continueOnCapturedContext">Whether async calls should continue on a captured synchronization context. <para><remarks>For <see cref="MemoryCacheProvider"/>, this parameter is irrelevant and is ignored, as the implementation is synchronous.</remarks></para></param>
77-
/// <returns>A <see cref="Task{TResult}" /> promising as Result the value from cache; or null, if none was found.</returns>
78-
public Task<object> GetAsync(string key, CancellationToken cancellationToken, bool continueOnCapturedContext)
74+
/// <param name="cancellationToken">The cancellation token.</param>
75+
/// <param name="continueOnCapturedContext">Whether async calls should continue on a captured synchronization context. <para><remarks>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.</remarks></para></param>
76+
/// <returns>
77+
/// A <see cref="Task{TResult}" /> promising as Result a tuple whose first element is a value indicating whether
78+
/// the key was found in the cache, and whose second element is the value from the cache (null if not found).
79+
/// </returns>
80+
public Task<(bool, object)> TryGetAsync(string key, CancellationToken cancellationToken, bool continueOnCapturedContext)
7981
{
8082
cancellationToken.ThrowIfCancellationRequested();
81-
return Task.FromResult(Get(key));
82-
// (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)
83+
return Task.FromResult(TryGet(key));
8384
}
8485

8586
/// <summary>
@@ -97,7 +98,6 @@ public Task PutAsync(string key, object value, Ttl ttl, CancellationToken cancel
9798
cancellationToken.ThrowIfCancellationRequested();
9899
Put(key, value, ttl);
99100
return Task.CompletedTask;
100-
// (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)
101101
}
102102
}
103103
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Xunit;
4+
5+
namespace Polly.Caching.Memory.Specs.Integration
6+
{
7+
public abstract class CacheRoundTripSpecsBase
8+
{
9+
protected CacheRoundTripSpecsBase(ICachePolicyFactory cachePolicyFactory)
10+
{
11+
CachePolicyFactory = cachePolicyFactory;
12+
}
13+
14+
protected ICachePolicyFactory CachePolicyFactory { get; }
15+
16+
protected const string OperationKey = "SomeOperationKey";
17+
18+
public abstract Task Should_roundtrip_this_variant_of<TResult>(TResult testValue);
19+
20+
[Theory]
21+
[MemberData(nameof(SampleClassData))]
22+
public async Task Should_roundtrip_all_variants_of_reference_type(SampleClass testValue)
23+
{
24+
await Should_roundtrip_this_variant_of<SampleClass>(testValue);
25+
}
26+
27+
[Theory]
28+
[MemberData(nameof(SampleStringData))]
29+
public async Task Should_roundtrip_all_variants_of_string(String testValue)
30+
{
31+
await Should_roundtrip_this_variant_of<String>(testValue);
32+
}
33+
34+
[Theory]
35+
[MemberData(nameof(SampleNumericData))]
36+
public async Task Should_roundtrip_all_variants_of_numeric(int testValue)
37+
{
38+
await Should_roundtrip_this_variant_of<int>(testValue);
39+
}
40+
41+
[Theory]
42+
[MemberData(nameof(SampleEnumData))]
43+
public async Task Should_roundtrip_all_variants_of_enum(SampleEnum testValue)
44+
{
45+
await Should_roundtrip_this_variant_of<SampleEnum>(testValue);
46+
}
47+
48+
[Theory]
49+
[MemberData(nameof(SampleBoolData))]
50+
public async Task Should_roundtrip_all_variants_of_bool(bool testValue)
51+
{
52+
await Should_roundtrip_this_variant_of<bool>(testValue);
53+
}
54+
55+
[Theory]
56+
[MemberData(nameof(SampleNullableBoolData))]
57+
public async Task Should_roundtrip_all_variants_of_nullable_bool(bool? testValue)
58+
{
59+
await Should_roundtrip_this_variant_of<bool?>(testValue);
60+
}
61+
62+
public static TheoryData<SampleClass> SampleClassData =>
63+
new TheoryData<SampleClass>
64+
{
65+
new SampleClass(),
66+
new SampleClass()
67+
{
68+
StringProperty = "<html></html>",
69+
IntProperty = 1
70+
},
71+
(SampleClass)null,
72+
default(SampleClass)
73+
};
74+
75+
public static TheoryData<String> SampleStringData =>
76+
new TheoryData<String>
77+
{
78+
"some string",
79+
"",
80+
null,
81+
default(string),
82+
"null"
83+
};
84+
85+
public static TheoryData<int> SampleNumericData =>
86+
new TheoryData<int>
87+
{
88+
-1,
89+
0,
90+
1,
91+
default(int)
92+
};
93+
94+
public static TheoryData<SampleEnum> SampleEnumData =>
95+
new TheoryData<SampleEnum>
96+
{
97+
SampleEnum.FirstValue,
98+
SampleEnum.SecondValue,
99+
default(SampleEnum),
100+
};
101+
102+
public static TheoryData<bool> SampleBoolData =>
103+
new TheoryData<bool>
104+
{
105+
true,
106+
false,
107+
default(bool),
108+
};
109+
110+
public static TheoryData<bool?> SampleNullableBoolData =>
111+
new TheoryData<bool?>
112+
{
113+
true,
114+
false,
115+
null,
116+
default(bool?),
117+
};
118+
119+
public class SampleClass
120+
{
121+
public string StringProperty { get; set; }
122+
public int IntProperty { get; set; }
123+
}
124+
125+
public enum SampleEnum
126+
{
127+
FirstValue,
128+
SecondValue,
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)