Skip to content

Commit bc06974

Browse files
authored
Merge pull request #186 from cnblogs/introduce-messagepack-serializer
Introduce MessagePack serializer
2 parents ee46b63 + 25fcbd3 commit bc06974

19 files changed

+329
-222
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ This is a .NET Core client library for Memcached migrated from [EnyimMemcached](
1212
"Address": "memcached",
1313
"Port": 11211
1414
}
15-
]
15+
],
16+
"Transcoder": "MessagePackTranscoder"
1617
}
1718
}
1819
```

sample/SampleWebApp/Controllers/HomeController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public async Task<IActionResult> Index()
4848

4949
public async Task<IActionResult> Postbody()
5050
{
51-
var postbody = (await _blogPostService.GetRecent(10)).First()?.Body;
51+
var postbody = (await _blogPostService.GetRecent(10)).First().Value.FirstOrDefault()?.Body;
5252
await _postbodyMemcachedClient.AddAsync(PostbodyCacheKey, postbody, 10);
5353
var result = await _postbodyMemcachedClient.GetAsync<string>(PostbodyCacheKey);
5454
return result.Success ? Ok() : StatusCode(500);

sample/SampleWebApp/Services/BlogPostService.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,21 @@ namespace Enyim.Caching.SampleWebApp.Services
88
{
99
public class BlogPostService : IBlogPostService
1010
{
11-
public async ValueTask<IEnumerable<BlogPost>> GetRecent(int itemCount)
11+
public async ValueTask<Dictionary<string, List<BlogPost>>> GetRecent(int itemCount)
1212
{
13-
return new List<BlogPost> { new BlogPost { Title = "Hello World", Body = "EnyimCachingCore" } };
13+
var dict = new Dictionary<string, List<BlogPost>>();
14+
var posts = new List<BlogPost>
15+
{
16+
new BlogPost
17+
{
18+
Title = "Hello World",
19+
Body = "EnyimCachingCore"
20+
}
21+
};
22+
23+
dict.Add(DateTime.Today.ToString("yyyy-MM-dd"), posts);
24+
25+
return dict;
1426
}
1527
}
1628
}

sample/SampleWebApp/Services/IBlogPostService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ namespace Enyim.Caching.SampleWebApp.Services
88
{
99
public interface IBlogPostService
1010
{
11-
ValueTask<IEnumerable<BlogPost>> GetRecent(int itemCount);
11+
ValueTask<Dictionary<string, List<BlogPost>>> GetRecent(int itemCount);
1212
}
1313
}

sample/SampleWebApp/appsettings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
"deadTimeout": "00:00:15",
1515
"queueTimeout": "00:00:00.150"
1616
},
17-
"suppressException": "false"
18-
//"Transcoder": "BinaryFormatterTranscoder"
17+
"suppressException": "false",
18+
"Transcoder": "MessagePackTranscoder"
1919
//,
2020
//"KeyTransformer": "Enyim.Caching.Memcached.SHA1KeyTransformer"
2121
//,
@@ -44,7 +44,7 @@
4444
"Default": "Warning",
4545
"System": "Warning",
4646
"Microsoft": "Warning",
47-
"Enyim": "Debug"
47+
"Enyim": "Warning"
4848
}
4949
}
5050
}

src/Enyim.Caching/Configuration/MemcachedClientConfiguration.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.Extensions.Configuration;
1010
using System.Linq;
1111
using System.Net.Sockets;
12+
using Enyim.Caching.Memcached.Transcoders;
1213

1314
namespace Enyim.Caching.Configuration
1415
{
@@ -153,8 +154,14 @@ public MemcachedClientConfiguration(
153154
{
154155
try
155156
{
156-
if (options.Transcoder == "BinaryFormatterTranscoder")
157+
if (options.Transcoder == nameof(BinaryFormatterTranscoder))
158+
{
157159
options.Transcoder = "Enyim.Caching.Memcached.Transcoders.BinaryFormatterTranscoder";
160+
}
161+
else if (options.Transcoder == nameof(MessagePackTranscoder))
162+
{
163+
options.Transcoder = "Enyim.Caching.Memcached.Transcoders.MessagePackTranscoder";
164+
}
158165

159166
var transcoderType = Type.GetType(options.Transcoder);
160167
if (transcoderType != null)
@@ -171,7 +178,7 @@ public MemcachedClientConfiguration(
171178
else if (transcoder != null)
172179
{
173180
_transcoder = transcoder;
174-
_logger.LogDebug($"Use Transcoder Type : '{transcoder.ToString()}'");
181+
_logger.LogDebug($"Use Transcoder Type : '{transcoder}'");
175182
}
176183

177184
if (options.NodeLocatorFactory != null)

src/Enyim.Caching/Enyim.Caching.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,8 @@
4242
</ItemGroup>
4343
</Otherwise>
4444
</Choose>
45+
46+
<ItemGroup>
47+
<PackageReference Include="MessagePack" Version="2.4.59" />
48+
</ItemGroup>
4549
</Project>

src/Enyim.Caching/IMemcachedClient.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ public interface IMemcachedClient : IDisposable
2929
Task<bool> ReplaceAsync(string key, object value, uint cacheSeconds);
3030
Task<bool> ReplaceAsync(string key, object value, TimeSpan timeSpan);
3131

32+
[Obsolete("Use GetAsync<T> instead")]
3233
Task<IGetOperationResult> GetAsync(string key);
3334
Task<IGetOperationResult<T>> GetAsync<T>(string key);
3435
Task<T> GetValueAsync<T>(string key);
3536
Task<T> GetValueOrCreateAsync<T>(string key, int cacheSeconds, Func<Task<T>> generator);
37+
[Obsolete("Use Get<T> instead")]
3638
object Get(string key);
3739
T Get<T>(string key);
3840
IDictionary<string, T> Get<T>(IEnumerable<string> keys);
3941
Task<IDictionary<string, T>> GetAsync<T>(IEnumerable<string> keys);
4042

43+
[Obsolete("Use TryGet<T> instead")]
4144
bool TryGet(string key, out object value);
4245
bool TryGet<T>(string key, out T value);
4346
bool TryGetWithCas(string key, out CasResult<object> value);

src/Enyim.Caching/Memcached/Transcoders/DefaultTranscoder.cs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,19 @@ protected virtual CacheItem Serialize(object value)
9191
{
9292
case (TypeCode)2: data = SerializeNull(); break; // TypeCode.DBNull
9393
case TypeCode.String: data = SerializeString(value.ToString()); break;
94-
case TypeCode.Boolean: data = SerializeBoolean((Boolean)value); break;
95-
case TypeCode.SByte: data = SerializeSByte((SByte)value); break;
96-
case TypeCode.Byte: data = SerializeByte((Byte)value); break;
97-
case TypeCode.Int16: data = SerializeInt16((Int16)value); break;
98-
case TypeCode.Int32: data = SerializeInt32((Int32)value); break;
99-
case TypeCode.Int64: data = SerializeInt64((Int64)value); break;
100-
case TypeCode.UInt16: data = SerializeUInt16((UInt16)value); break;
101-
case TypeCode.UInt32: data = SerializeUInt32((UInt32)value); break;
102-
case TypeCode.UInt64: data = SerializeUInt64((UInt64)value); break;
103-
case TypeCode.Char: data = SerializeChar((Char)value); break;
94+
case TypeCode.Boolean: data = SerializeBoolean((bool)value); break;
95+
case TypeCode.SByte: data = SerializeSByte((sbyte)value); break;
96+
case TypeCode.Byte: data = SerializeByte((byte)value); break;
97+
case TypeCode.Int16: data = SerializeInt16((short)value); break;
98+
case TypeCode.Int32: data = SerializeInt32((int)value); break;
99+
case TypeCode.Int64: data = SerializeInt64((long)value); break;
100+
case TypeCode.UInt16: data = SerializeUInt16((ushort)value); break;
101+
case TypeCode.UInt32: data = SerializeUInt32((uint)value); break;
102+
case TypeCode.UInt64: data = SerializeUInt64((ulong)value); break;
103+
case TypeCode.Char: data = SerializeChar((char)value); break;
104104
case TypeCode.DateTime: data = SerializeDateTime((DateTime)value); break;
105-
case TypeCode.Double: data = SerializeDouble((Double)value); break;
106-
case TypeCode.Single: data = SerializeSingle((Single)value); break;
105+
case TypeCode.Double: data = SerializeDouble((double)value); break;
106+
case TypeCode.Single: data = SerializeSingle((float)value); break;
107107
default:
108108
code = TypeCode.Object;
109109
data = SerializeObject(value);
@@ -280,47 +280,47 @@ protected virtual ArraySegment<byte> SerializeObject(object value)
280280
#endregion
281281
#region [ Typed deserialization ]
282282

283-
protected virtual String DeserializeString(ArraySegment<byte> value)
283+
protected virtual string DeserializeString(ArraySegment<byte> value)
284284
{
285285
return Encoding.UTF8.GetString(value.Array, value.Offset, value.Count);
286286
}
287287

288-
protected virtual Boolean DeserializeBoolean(ArraySegment<byte> value)
288+
protected virtual bool DeserializeBoolean(ArraySegment<byte> value)
289289
{
290290
return BitConverter.ToBoolean(value.Array, value.Offset);
291291
}
292292

293-
protected virtual Int16 DeserializeInt16(ArraySegment<byte> value)
293+
protected virtual short DeserializeInt16(ArraySegment<byte> value)
294294
{
295295
return BitConverter.ToInt16(value.Array, value.Offset);
296296
}
297297

298-
protected virtual Int32 DeserializeInt32(ArraySegment<byte> value)
298+
protected virtual int DeserializeInt32(ArraySegment<byte> value)
299299
{
300300
return BitConverter.ToInt32(value.Array, value.Offset);
301301
}
302302

303-
protected virtual Int64 DeserializeInt64(ArraySegment<byte> value)
303+
protected virtual long DeserializeInt64(ArraySegment<byte> value)
304304
{
305305
return BitConverter.ToInt64(value.Array, value.Offset);
306306
}
307307

308-
protected virtual UInt16 DeserializeUInt16(ArraySegment<byte> value)
308+
protected virtual ushort DeserializeUInt16(ArraySegment<byte> value)
309309
{
310310
return BitConverter.ToUInt16(value.Array, value.Offset);
311311
}
312312

313-
protected virtual UInt32 DeserializeUInt32(ArraySegment<byte> value)
313+
protected virtual uint DeserializeUInt32(ArraySegment<byte> value)
314314
{
315315
return BitConverter.ToUInt32(value.Array, value.Offset);
316316
}
317317

318-
protected virtual UInt64 DeserializeUInt64(ArraySegment<byte> value)
318+
protected virtual ulong DeserializeUInt64(ArraySegment<byte> value)
319319
{
320320
return BitConverter.ToUInt64(value.Array, value.Offset);
321321
}
322322

323-
protected virtual Char DeserializeChar(ArraySegment<byte> value)
323+
protected virtual char DeserializeChar(ArraySegment<byte> value)
324324
{
325325
return BitConverter.ToChar(value.Array, value.Offset);
326326
}
@@ -330,24 +330,24 @@ protected virtual DateTime DeserializeDateTime(ArraySegment<byte> value)
330330
return DateTime.FromBinary(BitConverter.ToInt64(value.Array, value.Offset));
331331
}
332332

333-
protected virtual Double DeserializeDouble(ArraySegment<byte> value)
333+
protected virtual double DeserializeDouble(ArraySegment<byte> value)
334334
{
335335
return BitConverter.ToDouble(value.Array, value.Offset);
336336
}
337337

338-
protected virtual Single DeserializeSingle(ArraySegment<byte> value)
338+
protected virtual float DeserializeSingle(ArraySegment<byte> value)
339339
{
340340
return BitConverter.ToSingle(value.Array, value.Offset);
341341
}
342342

343-
protected virtual Byte DeserializeByte(ArraySegment<byte> data)
343+
protected virtual byte DeserializeByte(ArraySegment<byte> data)
344344
{
345345
return data.Array[data.Offset];
346346
}
347347

348-
protected virtual SByte DeserializeSByte(ArraySegment<byte> data)
348+
protected virtual sbyte DeserializeSByte(ArraySegment<byte> data)
349349
{
350-
return (SByte)data.Array[data.Offset];
350+
return (sbyte)data.Array[data.Offset];
351351
}
352352

353353
protected virtual object DeserializeObject(ArraySegment<byte> value)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using MessagePack;
2+
using MessagePack.Resolvers;
3+
using Microsoft.Extensions.Options;
4+
using Newtonsoft.Json.Bson;
5+
using Newtonsoft.Json.Linq;
6+
using System;
7+
using System.Collections;
8+
using System.Collections.Generic;
9+
using System.Collections.Immutable;
10+
using System.IO;
11+
using System.Reflection;
12+
using System.Runtime.CompilerServices;
13+
using System.Text;
14+
15+
namespace Enyim.Caching.Memcached.Transcoders
16+
{
17+
public class MessagePackTranscoder : DefaultTranscoder
18+
{
19+
private readonly MessagePackSerializerOptions _options;
20+
21+
public MessagePackTranscoder() : this(CreateDefaultOptions())
22+
{
23+
}
24+
25+
public MessagePackTranscoder(MessagePackSerializerOptions options)
26+
{
27+
_options = options ?? CreateDefaultOptions();
28+
}
29+
30+
protected override ArraySegment<byte> SerializeObject(object value)
31+
{
32+
var bytes = MessagePackSerializer.Serialize(value, _options);
33+
return new ArraySegment<byte>(bytes, 0, bytes.Length);
34+
}
35+
36+
protected override object DeserializeObject(ArraySegment<byte> value)
37+
{
38+
throw new NotSupportedException("Does not support typeless deserialization. Please use generic api.");
39+
}
40+
41+
public override T Deserialize<T>(CacheItem item)
42+
{
43+
if (typeof(T).GetTypeCode() != TypeCode.Object || typeof(T) == typeof(byte[]))
44+
{
45+
var value = Deserialize(item);
46+
if (value != null)
47+
{
48+
if (typeof(T) == typeof(Guid))
49+
{
50+
return (T)(object)new Guid((string)value);
51+
}
52+
else
53+
{
54+
return (T)value;
55+
}
56+
}
57+
else
58+
{
59+
return default;
60+
}
61+
}
62+
63+
return MessagePackSerializer.Deserialize<T>(item.Data, _options);
64+
}
65+
66+
private static MessagePackSerializerOptions CreateDefaultOptions()
67+
{
68+
var resolver = CompositeResolver.Create(
69+
NativeDateTimeResolver.Instance,
70+
NativeGuidResolver.Instance,
71+
NativeDecimalResolver.Instance,
72+
ContractlessStandardResolverAllowPrivate.Instance,
73+
ContractlessStandardResolver.Instance);
74+
return MessagePackSerializerOptions.Standard.WithResolver(resolver);
75+
}
76+
}
77+
}

test/DistributedCacheTests/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"Address": "memcached",
66
"Port": 11211
77
}
8-
]
8+
],
9+
"Transcoder": "MessagePackTranscoder"
910
}
1011
}

test/Enyim.Caching.Tests/MemcachedClientCasTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public async Task When_Storing_Item_With_Valid_Cas_Result_Is_Successful_Async()
4747
var storeResult = Store(StoreMode.Add, key, comment);
4848
StoreAssertPass(storeResult);
4949

50-
var casResult1 = await _client.GetAsync(key);
50+
var casResult1 = await _client.GetAsync<Comment>(key);
5151
GetAssertPass(casResult1, comment);
5252

5353
var casResult2 = await _client.GetAsync<Comment>(key);

0 commit comments

Comments
 (0)