Skip to content

Commit 6d74c8d

Browse files
committed
Fix HybridCache's (de)serialization issue, Close #320
1 parent 516c1c8 commit 6d74c8d

14 files changed

+271
-32
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>5.3.5</VersionPrefix>
3+
<VersionPrefix>5.3.6</VersionPrefix>
44
<LangVersion>latest</LangVersion>
55
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
66
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>

src/EFCoreSecondLevelCacheInterceptor/EFTableRowsDataReader.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
using System;
2-
using System.Collections;
3-
using System.Collections.Generic;
1+
using System.Collections;
42
using System.Data;
53
using System.Data.Common;
64
using System.Globalization;
7-
using System.Linq;
85
#if NET10_0 || NET9_0 || NET8_0 || NET7_0 || NET6_0 || NET5_0
96
using System.Text.Json;
107
#endif
@@ -453,6 +450,13 @@ public override int GetInt32(int ordinal)
453450
return (int)(long)value;
454451
}
455452

453+
#if NET10_0 || NET9_0 || NET8_0 || NET7_0 || NET6_0 || NET5_0
454+
if (valueType == TypeExtensions.JsonElement)
455+
{
456+
return ((JsonElement)value).GetInt32();
457+
}
458+
#endif
459+
456460
if (valueType != TypeExtensions.IntType)
457461
{
458462
return (int)Convert.ChangeType(value, TypeExtensions.IntType, CultureInfo.InvariantCulture);

src/EFCoreSecondLevelCacheInterceptor/TypeExtensions.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using System;
2-
using System.Collections.Generic;
1+
#if NET10_0 || NET9_0 || NET8_0 || NET7_0 || NET6_0 || NET5_0
2+
using System.Text.Json;
3+
#endif
34

45
namespace EFCoreSecondLevelCacheInterceptor;
56

@@ -8,6 +9,13 @@ namespace EFCoreSecondLevelCacheInterceptor;
89
/// </summary>
910
public static class TypeExtensions
1011
{
12+
#if NET10_0 || NET9_0 || NET8_0 || NET7_0 || NET6_0 || NET5_0
13+
/// <summary>
14+
/// Cached version of typeof(JsonElement)
15+
/// </summary>
16+
public static readonly Type JsonElement = typeof(JsonElement);
17+
#endif
18+
1119
/// <summary>
1220
/// Cached version of typeof(long)
1321
/// </summary>
4 KB
Binary file not shown.

src/Tests/Issues/Issue9SQLiteInt32/EFServiceProvider.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using EFCoreSecondLevelCacheInterceptor;
33
using Issue9SQLiteInt32.DataLayer;
44
using Microsoft.EntityFrameworkCore;
5+
using Microsoft.Extensions.Caching.Hybrid;
56
using Microsoft.Extensions.Configuration;
67
using Microsoft.Extensions.DependencyInjection;
78
using Microsoft.Extensions.Logging;
@@ -54,12 +55,24 @@ private static IServiceProvider getServiceProvider()
5455

5556
services.AddSingleton(_ => configuration);
5657

57-
services.AddEFSecondLevelCache(options
58-
=> options.UseMemoryCacheProvider(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(minutes: 5))
59-
.ConfigureLogging(enable: true)
58+
services.AddEFSecondLevelCache(options => options
6059

61-
//options.UseCacheManagerCoreProvider()
62-
);
60+
//.UseMemoryCacheProvider(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(minutes: 5))
61+
//.UseCacheManagerCoreProvider()
62+
.UseHybridCacheProvider(CacheExpirationMode.Absolute, TimeSpan.FromHours(hours: 1))
63+
.ConfigureLogging(enable: true)
64+
.UseDbCallsIfCachingProviderIsDown(TimeSpan.FromMinutes(minutes: 1)));
65+
66+
services.AddHybridCache(options =>
67+
{
68+
options.DefaultEntryOptions = new HybridCacheEntryOptions
69+
{
70+
Expiration = TimeSpan.FromHours(hours: 1),
71+
LocalCacheExpiration = TimeSpan.FromHours(hours: 1)
72+
};
73+
});
74+
75+
//.AddSerializerFactory<MessagePackSerializerFactory>()
6376

6477
addCacheManagerCoreRedis(services);
6578

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Buffers;
2+
using MessagePack;
3+
using Microsoft.Extensions.Caching.Hybrid;
4+
5+
namespace Issue9SQLiteInt32.HybridCache.Serializers;
6+
7+
public class CustomMessagePackSerializer<T> : IHybridCacheSerializer<T>
8+
{
9+
public T Deserialize(ReadOnlySequence<byte> source)
10+
=> MessagePackSerializer.Deserialize<T>(source, CustomMessagePackSerializerOptions.SerializerOptions);
11+
12+
public void Serialize(T value, IBufferWriter<byte> target)
13+
=> MessagePackSerializer.Serialize(target, value, CustomMessagePackSerializerOptions.SerializerOptions);
14+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using MessagePack;
2+
using MessagePack.Formatters;
3+
using MessagePack.Resolvers;
4+
5+
namespace Issue9SQLiteInt32.HybridCache.Serializers;
6+
7+
public static class CustomMessagePackSerializerOptions
8+
{
9+
private static readonly IFormatterResolver CustomResolvers = CompositeResolver.Create(
10+
[
11+
MessagePackDBNullFormatter.Instance, NativeDateTimeArrayFormatter.Instance,
12+
NativeDateTimeFormatter.Instance,
13+
NativeDecimalFormatter.Instance, NativeGuidFormatter.Instance, TypelessFormatter.Instance
14+
],
15+
[
16+
NativeDateTimeResolver.Instance, NativeDecimalResolver.Instance, NativeGuidResolver.Instance,
17+
ContractlessStandardResolver.Instance, StandardResolverAllowPrivate.Instance,
18+
TypelessContractlessStandardResolver.Instance, DynamicGenericResolver.Instance
19+
]);
20+
21+
public static readonly MessagePackSerializerOptions SerializerOptions = MessagePackSerializerOptions.Standard
22+
.WithCompression(MessagePackCompression.Lz4BlockArray)
23+
.WithResolver(CustomResolvers);
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using MessagePack;
2+
using MessagePack.Formatters;
3+
4+
namespace Issue9SQLiteInt32.HybridCache.Serializers;
5+
6+
/// <summary>
7+
/// The contract for serialization of some specific type.
8+
/// </summary>
9+
public class MessagePackDBNullFormatter : IMessagePackFormatter<DBNull?>
10+
{
11+
/// <summary>
12+
/// DBNullFormatter instance
13+
/// </summary>
14+
public static readonly MessagePackDBNullFormatter Instance = new();
15+
16+
private MessagePackDBNullFormatter()
17+
{
18+
}
19+
20+
/// <inheritdoc />
21+
public void Serialize(ref MessagePackWriter writer, DBNull? value, MessagePackSerializerOptions options)
22+
=> writer.WriteNil();
23+
24+
/// <inheritdoc />
25+
public DBNull Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => DBNull.Value;
26+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using Microsoft.Extensions.Caching.Hybrid;
3+
4+
namespace Issue9SQLiteInt32.HybridCache.Serializers;
5+
6+
public class MessagePackSerializerFactory : IHybridCacheSerializerFactory
7+
{
8+
public bool TryCreateSerializer<T>([NotNullWhen(returnValue: true)] out IHybridCacheSerializer<T>? serializer)
9+
{
10+
serializer = new CustomMessagePackSerializer<T>();
11+
12+
return true;
13+
}
14+
15+
protected virtual bool SupportsType<T>() => true;
16+
17+
}

src/Tests/Issues/Issue9SQLiteInt32/Issue9SQLiteInt32.csproj

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,27 @@
55
</PropertyGroup>
66
<ItemGroup>
77
<ProjectReference Include="..\..\..\EFCoreSecondLevelCacheInterceptor.MemoryCache\EFCoreSecondLevelCacheInterceptor.MemoryCache.csproj"/>
8+
<ProjectReference Include="..\..\..\EFCoreSecondLevelCacheInterceptor.HybridCache\EFCoreSecondLevelCacheInterceptor.HybridCache.csproj"/>
89
<ProjectReference Include="..\..\..\EFCoreSecondLevelCacheInterceptor\EFCoreSecondLevelCacheInterceptor.csproj"/>
910
</ItemGroup>
1011
<ItemGroup>
11-
<PackageReference Include="Microsoft.EntityFrameworkCore" />
12-
<PackageReference Include="Microsoft.Extensions.Logging" />
13-
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
14-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
12+
<PackageReference Include="MessagePack"/>
13+
<PackageReference Include="Microsoft.EntityFrameworkCore"/>
14+
<PackageReference Include="Microsoft.Extensions.Logging"/>
15+
<PackageReference Include="Microsoft.Extensions.Logging.Console"/>
16+
<PackageReference Include="Microsoft.Extensions.Configuration.Json"/>
1517
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
1618
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1719
<PrivateAssets>all</PrivateAssets>
1820
</PackageReference>
1921
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions"/>
20-
<PackageReference Include="Microsoft.Extensions.Logging.Debug" />
21-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
22-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" />
23-
<PackageReference Include="CacheManager.StackExchange.Redis" />
24-
<PackageReference Include="CacheManager.Core" />
25-
<PackageReference Include="CacheManager.Microsoft.Extensions.Caching.Memory" />
26-
<PackageReference Include="CacheManager.Serialization.Json" />
22+
<PackageReference Include="Microsoft.Extensions.Logging.Debug"/>
23+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite"/>
24+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core"/>
25+
<PackageReference Include="CacheManager.StackExchange.Redis"/>
26+
<PackageReference Include="CacheManager.Core"/>
27+
<PackageReference Include="CacheManager.Microsoft.Extensions.Caching.Memory"/>
28+
<PackageReference Include="CacheManager.Serialization.Json"/>
2729
</ItemGroup>
2830

2931
<ItemGroup>

0 commit comments

Comments
 (0)