diff --git a/EasyCaching.sln b/EasyCaching.sln
index 3f2504a3..7d07ad0a 100644
--- a/EasyCaching.sln
+++ b/EasyCaching.sln
@@ -1,4 +1,4 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
@@ -76,6 +76,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.Bus.Zookeeper",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.FasterKv", "src\EasyCaching.FasterKv\EasyCaching.FasterKv.csproj", "{7191E567-38DF-4879-82E1-73EC618AFCAC}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.Serialization.MemoryPack", "serialization\EasyCaching.Serialization.MemoryPack\EasyCaching.Serialization.MemoryPack.csproj", "{EEF22C21-F380-4980-B72C-F14488369333}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -202,6 +204,10 @@ Global
{7191E567-38DF-4879-82E1-73EC618AFCAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7191E567-38DF-4879-82E1-73EC618AFCAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7191E567-38DF-4879-82E1-73EC618AFCAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EEF22C21-F380-4980-B72C-F14488369333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EEF22C21-F380-4980-B72C-F14488369333}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EEF22C21-F380-4980-B72C-F14488369333}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EEF22C21-F380-4980-B72C-F14488369333}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -237,6 +243,7 @@ Global
{F7FBADEB-D766-4595-949A-07104B52692C} = {B337509B-75F9-4851-821F-9BBE87C4E4BC}
{5E488583-391E-4E15-83C1-7301B4FE79AE} = {B337509B-75F9-4851-821F-9BBE87C4E4BC}
{7191E567-38DF-4879-82E1-73EC618AFCAC} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9}
+ {EEF22C21-F380-4980-B72C-F14488369333} = {15070C49-A507-4844-BCFE-D319CFBC9A63}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63A57886-054B-476C-AAE1-8D7C8917682E}
diff --git a/sample/EasyCaching.Demo.ConsoleApp/EasyCaching.Demo.ConsoleApp.csproj b/sample/EasyCaching.Demo.ConsoleApp/EasyCaching.Demo.ConsoleApp.csproj
index 91b6c494..10bc10bd 100644
--- a/sample/EasyCaching.Demo.ConsoleApp/EasyCaching.Demo.ConsoleApp.csproj
+++ b/sample/EasyCaching.Demo.ConsoleApp/EasyCaching.Demo.ConsoleApp.csproj
@@ -20,10 +20,13 @@
+
+
+
+
-
+
-
diff --git a/sample/EasyCaching.Demo.ConsoleApp/Program.cs b/sample/EasyCaching.Demo.ConsoleApp/Program.cs
index 03f7b282..3885d5ee 100644
--- a/sample/EasyCaching.Demo.ConsoleApp/Program.cs
+++ b/sample/EasyCaching.Demo.ConsoleApp/Program.cs
@@ -1,9 +1,10 @@
-using System.Threading.Tasks;
+using EasyCaching.Serialization.MemoryPack;
namespace EasyCaching.Demo.ConsoleApp
{
using EasyCaching.Core;
using EasyCaching.SQLite;
+ using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -16,15 +17,18 @@ static void Main(string[] args)
IServiceCollection services = new ServiceCollection();
services.AddEasyCaching(option =>
{
+ option.WithMemoryPack(configure =>
+ {
+ }, "mempack");
+
option.UseInMemory("m1");
- // option.UseRedis(config =>
- // {
- // config.DBConfig = new Redis.RedisDBOptions { Configuration = "localhost" };
- // config.SerializerName = "json";
- // }, "r1");
- //
-
+ option.UseRedis((options) =>
+ {
+ options.SerializerName = "mempack";
+ options.DBConfig.Endpoints.Add(new Core.Configurations.ServerEndPoint("localhost", 6388));
+ }, "r1");
+
option.UseSQLite(c =>
{
c.DBConfig = new SQLiteDBOptions
@@ -43,7 +47,7 @@ static void Main(string[] args)
IServiceProvider serviceProvider = services.BuildServiceProvider();
var factory = serviceProvider.GetService();
-
+
// var redisCache = factory.GetCachingProvider("r1");
//
// redisCache.Set("rkey", new Product() { Name = "test" }, TimeSpan.FromSeconds(20));
@@ -55,41 +59,63 @@ static void Main(string[] args)
// Console.WriteLine($"redis cache get value, {redisVal.HasValue} {redisVal.IsNull} {redisVal.Value}");
-
- var mCache = factory.GetCachingProvider("m1");
-
- mCache.Set("mkey1", new Product() { Name = "test" }, TimeSpan.FromSeconds(20));
- var mVal1 = mCache.Get("mkey1");
+ var rCache = factory.GetCachingProvider("r1");
+
+ var prod = new Product()
+ {
+ Name = "Name1",
+ Lastname = "Lastname1",
+ Inner = new()
+ {
+ Name = "Name2",
+ Lastname = "Lastname2"
+ }
+ };
+
+ prod.Inner.Inner = prod;
+ rCache.Set("mkey1", prod, TimeSpan.FromSeconds(20));
+
+ var mVal1 = rCache.Get("mkey1");
+
+ rCache.Set("mkey", "mvalue", TimeSpan.FromSeconds(20));
+
+ var mVal = rCache.Get("mkey");
+
+ var mAllKey = rCache.GetAllKeysByPrefix("mk");
- mCache.Set("mkey", "mvalue", TimeSpan.FromSeconds(20));
-
- var mVal = mCache.Get("mkey");
-
- var mAllKey = mCache.GetAllKeysByPrefix("mk");
-
Console.WriteLine($"in-memory cache get value, {mVal.HasValue} {mVal.IsNull} {mVal.Value} ");
-
+
var sCache = factory.GetCachingProvider("s1");
-
+
sCache.Set("skey", "svalue", TimeSpan.FromSeconds(20));
-
+
var sVal = sCache.Get("skey");
-
+
Console.WriteLine($"sqlite cache get value, {sVal.HasValue} {sVal.IsNull} {sVal.Value} ");
Console.ReadKey();
}
}
- public class Product
+ [MemoryPackable(GenerateType.CircularReference)]
+ public partial class Product
{
+ [MemoryPackOrder(0)]
public string Name { get; set; }
+
+ [MemoryPackOrder(1)]
+
+ public string Lastname { get; set; }
+
+ [MemoryPackOrder(2)]
+
+ public Product Inner { set; get; }
}
}
diff --git a/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingMemPackSerializerOptions.cs b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingMemPackSerializerOptions.cs
new file mode 100644
index 00000000..033aa04d
--- /dev/null
+++ b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingMemPackSerializerOptions.cs
@@ -0,0 +1,13 @@
+using MemoryPack;
+
+namespace EasyCaching.Serialization.MemoryPack;
+
+///
+/// EasyCaching memory pack serializer options.
+///
+public record EasyCachingMemPackSerializerOptions
+{
+ public StringEncoding StringEncoding { set; get; }
+}
+
+
diff --git a/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingOptionsExtensions.cs b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingOptionsExtensions.cs
new file mode 100644
index 00000000..6764f372
--- /dev/null
+++ b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/EasyCachingOptionsExtensions.cs
@@ -0,0 +1,36 @@
+using MemoryPack;
+using EasyCaching.Core.Configurations;
+using EasyCaching.Serialization.Json;
+
+namespace EasyCaching.Serialization.MemoryPack;
+
+///
+/// Easy caching options extensions.
+///
+public static class EasyCachingOptionsExtensions
+{
+ ///
+ /// Withs the memory pack serializer.
+ ///
+ /// Options.
+ /// The name of this serializer instance.
+ public static EasyCachingOptions WithMemoryPack(this EasyCachingOptions options, string name = "mempack")
+ {
+ options.RegisterExtension(new MemoryPackOptionsExtension(name, null));
+
+ return options;
+ }
+
+ ///
+ /// Withs the memory pack serializer.
+ ///
+ /// Options.
+ /// Configure serializer settings.
+ /// The name of this serializer instance.
+ public static EasyCachingOptions WithMemoryPack(this EasyCachingOptions options, Action serializerOptions, string name)
+ {
+ options.RegisterExtension(new MemoryPackOptionsExtension(name, serializerOptions));
+
+ return options;
+ }
+}
diff --git a/serialization/EasyCaching.Serialization.MemoryPack/Configurations/MemoryPackOptionsExtension.cs b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/MemoryPackOptionsExtension.cs
new file mode 100644
index 00000000..58126711
--- /dev/null
+++ b/serialization/EasyCaching.Serialization.MemoryPack/Configurations/MemoryPackOptionsExtension.cs
@@ -0,0 +1,55 @@
+namespace EasyCaching.Serialization.Json;
+
+using System;
+using EasyCaching.Core.Configurations;
+using EasyCaching.Core.Serialization;
+using EasyCaching.Serialization.MemoryPack;
+using global::MemoryPack;
+using Microsoft.Extensions.DependencyInjection;
+
+///
+/// MemoryPack options extension.
+///
+internal sealed class MemoryPackOptionsExtension : IEasyCachingOptionsExtension
+{
+ ///
+ /// The name.
+ ///
+ private readonly string _name;
+
+ ///
+ /// The configure.
+ ///
+ private readonly Action _configure;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Name.
+ /// Configure.
+ public MemoryPackOptionsExtension(string name, Action configure)
+ {
+ this._name = name;
+ this._configure = configure;
+ }
+
+ ///
+ /// Adds the services.
+ ///
+ /// Services.
+ public void AddServices(IServiceCollection services)
+ {
+ Action configure = _configure ?? (_ => { });
+
+ services.AddOptions();
+ services.Configure(_name, configure);
+
+ services.AddSingleton(x =>
+ {
+ var optionsMon = x.GetRequiredService>();
+ var easyCachingOptions = optionsMon.Get(_name);
+ var options = new MemoryPackSerializerOptions { StringEncoding = easyCachingOptions.StringEncoding };
+ return new DefaultMemoryPackSerializer(_name, options);
+ });
+ }
+}
diff --git a/serialization/EasyCaching.Serialization.MemoryPack/DefaultMemoryPackSerializer.cs b/serialization/EasyCaching.Serialization.MemoryPack/DefaultMemoryPackSerializer.cs
new file mode 100644
index 00000000..e8d01528
--- /dev/null
+++ b/serialization/EasyCaching.Serialization.MemoryPack/DefaultMemoryPackSerializer.cs
@@ -0,0 +1,33 @@
+using EasyCaching.Core.Serialization;
+using MemoryPack;
+
+namespace EasyCaching.Serialization.MemoryPack;
+
+///
+/// Default MemoryPack serializer
+///
+public class DefaultMemoryPackSerializer : IEasyCachingSerializer
+{
+ private readonly string _name;
+ private readonly MemoryPackSerializerOptions _memoryPackSerializerOptions;
+
+ public string Name => _name;
+
+ public DefaultMemoryPackSerializer(string name, MemoryPackSerializerOptions options = null)
+ {
+ _name = name;
+ _memoryPackSerializerOptions = options;
+ }
+
+ public T Deserialize(byte[] bytes) => MemoryPackSerializer.Deserialize(bytes, _memoryPackSerializerOptions);
+ public object Deserialize(byte[] bytes, Type type) => MemoryPackSerializer.Deserialize(type, bytes, _memoryPackSerializerOptions);
+ public object DeserializeObject(ArraySegment value) => throw new NotImplementedException("this is not supported in MemoryPack serializer");
+ public byte[] Serialize(T value) => MemoryPackSerializer.Serialize(value, _memoryPackSerializerOptions);
+
+ public ArraySegment SerializeObject(object obj)
+ {
+ var bytes = MemoryPackSerializer.Serialize(obj.GetType(), obj, _memoryPackSerializerOptions);
+ return new ArraySegment(bytes);
+ }
+}
+
diff --git a/serialization/EasyCaching.Serialization.MemoryPack/EasyCaching.Serialization.MemoryPack.csproj b/serialization/EasyCaching.Serialization.MemoryPack/EasyCaching.Serialization.MemoryPack.csproj
new file mode 100644
index 00000000..91d53fd7
--- /dev/null
+++ b/serialization/EasyCaching.Serialization.MemoryPack/EasyCaching.Serialization.MemoryPack.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net6.0
+ enable
+
+
+
+
+
+
+
+
diff --git a/test/EasyCaching.UnitTests/CachingTests/BaseCachingProviderTest.cs b/test/EasyCaching.UnitTests/CachingTests/BaseCachingProviderTest.cs
index 9b359f10..0e70a5ba 100644
--- a/test/EasyCaching.UnitTests/CachingTests/BaseCachingProviderTest.cs
+++ b/test/EasyCaching.UnitTests/CachingTests/BaseCachingProviderTest.cs
@@ -765,7 +765,7 @@ public async Task Remove_Cached_Value_Async_Should_Succeed()
var cacheValue = "value";
await _provider.SetAsync(cacheKey, cacheValue, _defaultTs);
- var valBeforeRemove = await _provider.GetAsync(cacheKey, null, _defaultTs);
+ var valBeforeRemove = await _provider.GetAsync(cacheKey, () => null, _defaultTs);
Assert.NotNull(valBeforeRemove);
await _provider.RemoveAsync(cacheKey);
@@ -870,7 +870,7 @@ protected virtual async Task RemoveByPrefixAsync_Should_Succeed()
}
#endregion
-
+
#region RemoveByPattern/RemoveByPatternAsync
[Fact]
@@ -878,7 +878,7 @@ public virtual void RemoveByPattern_Should_Succeed()
{
SetCacheItem("garden:pots:flowers", "ok");
SetCacheItem("garden:pots:flowers:test", "ok");
- SetCacheItem("garden:flowerspots:test", "ok" );
+ SetCacheItem("garden:flowerspots:test", "ok");
SetCacheItem("boo:foo", "ok");
SetCacheItem("boo:test:foo", "ok");
SetCacheItem("sky:birds:bar", "ok");
@@ -933,13 +933,13 @@ public virtual void RemoveByPattern_Should_Succeed()
Assert.False(val15.HasValue);
Assert.False(val16.HasValue);
}
-
+
[Fact]
public virtual async Task RemoveByPatternAsync_Should_Succeed()
{
SetCacheItem("garden:pots:flowers", "ok");
SetCacheItem("garden:pots:flowers:test", "ok");
- SetCacheItem("garden:flowerspots:test", "ok" );
+ SetCacheItem("garden:flowerspots:test", "ok");
SetCacheItem("boo:foo", "ok");
SetCacheItem("boo:test:foo", "ok");
SetCacheItem("sky:birds:bar", "ok");
diff --git a/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj b/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj
index 26b51b1d..4c5c5b3b 100644
--- a/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj
+++ b/test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj
@@ -30,15 +30,6 @@
-
-
-
-
-
-
-
-
-
@@ -51,4 +42,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/EasyCaching.UnitTests/SerializerTests/BaseSerializerTest.cs b/test/EasyCaching.UnitTests/SerializerTests/BaseSerializerTest.cs
index 49dbcda4..bfc5a26d 100644
--- a/test/EasyCaching.UnitTests/SerializerTests/BaseSerializerTest.cs
+++ b/test/EasyCaching.UnitTests/SerializerTests/BaseSerializerTest.cs
@@ -2,6 +2,7 @@
{
using System;
using EasyCaching.Core.Serialization;
+ using MemoryPack;
using ProtoBuf;
using Xunit;
@@ -38,7 +39,7 @@ public void SerializeObject_should_Succeed()
}
[Fact]
- public void DeserializeObject_should_Succeed()
+ public virtual void DeserializeObject_should_Succeed()
{
object obj = new Model { Prop = "abc" };
@@ -76,7 +77,8 @@ public void Deserialize_String_Should_Succeed(string str)
[Serializable]
[ProtoContract]
- public class Model
+ [MemoryPackable]
+ public partial class Model
{
[ProtoMember(1)]
public string Prop { get; set; }
diff --git a/test/EasyCaching.UnitTests/SerializerTests/MemoryPackSerializerTest.cs b/test/EasyCaching.UnitTests/SerializerTests/MemoryPackSerializerTest.cs
new file mode 100644
index 00000000..32cbbfb9
--- /dev/null
+++ b/test/EasyCaching.UnitTests/SerializerTests/MemoryPackSerializerTest.cs
@@ -0,0 +1,96 @@
+using System;
+using EasyCaching.Serialization.MemoryPack;
+using MemoryPack;
+using Xunit;
+
+namespace EasyCaching.UnitTests;
+
+
+public class MemoryPackSerializerTest : BaseSerializerTest
+{
+ public MemoryPackSerializerTest()
+ {
+ _serializer = new DefaultMemoryPackSerializer("mempack");
+ }
+
+ //This should be overrided becuse it is not supported by memory-pack
+ public override void DeserializeObject_should_Succeed()
+ {
+ Person input = new("test", "test1");
+ var serialized = _serializer.Serialize(input);
+
+ Assert.Throws(() =>
+ {
+ _serializer.DeserializeObject(new System.ArraySegment(serialized));
+ });
+ }
+
+ [Fact]
+ public void GivenSampleRecord_ShouldSerializeAndDeserializeSuccessfuly()
+ {
+ Person input = new("test", "test1");
+ var bytes = _serializer.Serialize(input);
+
+ Person output = _serializer.Deserialize(bytes);
+
+ Assert.Equal(input, output);
+ }
+
+ [Fact]
+ public void GivenSampleRecord_ShouldHandleNestedObjectSuccessfuly()
+ {
+ NestedPerson item1 = new() { Name = "test", Lastname = "test1" };
+ NestedPerson expected = new() { Name = "test2", Lastname = "test3", Inner = item1 };
+
+ var bytes = _serializer.Serialize(expected);
+
+ NestedPerson output = _serializer.Deserialize(bytes);
+
+ Assert.Equal(expected, output);
+ }
+
+ [Fact]
+ public void GivenSampleInput_ShouldHandleCircularRefSuccessfuly()
+ {
+ CircularPerson person = new CircularPerson()
+ {
+ Name = "test"
+ };
+
+ person.Self = person;
+
+ var bytes = _serializer.Serialize(person);
+ var output = _serializer.Deserialize(bytes);
+
+ bool expected =
+ person.Name == output.Name &&
+ output.Self == output &&
+ output.Name == output.Self.Name;
+
+ Assert.True(expected);
+ }
+}
+
+#region Test Models
+[MemoryPackable(GenerateType.CircularReference)]
+internal partial class CircularPerson
+{
+ [MemoryPackOrder(0)]
+ public string Name { set; get; }
+ [MemoryPackOrder(1)]
+ public CircularPerson Self { set; get; }
+}
+
+[MemoryPackable]
+internal partial record struct Person(string Name, string Lastname);
+
+[MemoryPackable]
+internal partial record class NestedPerson
+{
+ public string Name { set; get; }
+
+ public string Lastname { set; get; }
+
+ public NestedPerson Inner { set; get; }
+}
+#endregion