forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMsgPackFormat.cs
More file actions
156 lines (130 loc) · 4.69 KB
/
MsgPackFormat.cs
File metadata and controls
156 lines (130 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using MsgPack;
using MsgPack.Serialization;
using ServiceStack.Web;
namespace ServiceStack.MsgPack
{
public class MsgPackType<T> : IMsgPackType
{
private static readonly Type type;
private static bool isGenericCollection;
private static Func<object, Type, object> collectionConvertFn;
static MsgPackType()
{
var genericType = typeof(T).FirstGenericType();
isGenericCollection = genericType != null
&& typeof(T).IsOrHasGenericInterfaceTypeOf(typeof(ICollection<>));
if (isGenericCollection)
{
var elType = genericType.GetGenericArguments()[0];
var genericMi = typeof(CollectionExtensions).GetStaticMethod("Convert");
var mi = genericMi.MakeGenericMethod(elType);
collectionConvertFn = (Func<object, Type, object>)
mi.CreateDelegate(typeof(Func<object, Type, object>));
}
type = isGenericCollection ? genericType : typeof(T);
}
public Type Type
{
get
{
return type;
}
}
public object Convert(object instance)
{
if (!isGenericCollection)
return instance;
var ret = collectionConvertFn(instance, typeof(T));
return ret;
}
}
internal interface IMsgPackType
{
Type Type { get; }
object Convert(object instance);
}
public class MsgPackFormat : IPlugin, IMsgPackPlugin
{
public void Register(IAppHost appHost)
{
appHost.ContentTypes.Register(MimeTypes.MsgPack,
Serialize,
Deserialize);
}
private static Dictionary<Type, IMsgPackType> msgPackTypeCache = new Dictionary<Type, IMsgPackType>();
internal static IMsgPackType GetMsgPackType(Type type)
{
IMsgPackType msgPackType;
if (msgPackTypeCache.TryGetValue(type, out msgPackType))
return msgPackType;
var genericType = typeof(MsgPackType<>).MakeGenericType(type);
msgPackType = (IMsgPackType)genericType.CreateInstance();
Dictionary<Type, IMsgPackType> snapshot, newCache;
do
{
snapshot = msgPackTypeCache;
newCache = new Dictionary<Type, IMsgPackType>(msgPackTypeCache) {[type] = msgPackType};
} while (!ReferenceEquals(
Interlocked.CompareExchange(ref msgPackTypeCache, newCache, snapshot), snapshot));
return msgPackType;
}
public static void Serialize(IRequest requestContext, object dto, Stream outputStream)
{
Serialize(dto, outputStream);
}
public static void Serialize(object dto, Stream outputStream)
{
if (dto == null) return;
var dtoType = dto.GetType();
try
{
var msgPackType = GetMsgPackType(dtoType);
dtoType = msgPackType.Type;
var serializer = MessagePackSerializer.Get(dtoType);
serializer.PackTo(Packer.Create(outputStream), dto);
}
catch (Exception ex)
{
HandleException(ex, dtoType);
}
}
public static object Deserialize(Type type, Stream fromStream)
{
try
{
var msgPackType = GetMsgPackType(type);
type = msgPackType.Type;
var serializer = MessagePackSerializer.Get(type);
var unpacker = Unpacker.Create(fromStream);
unpacker.Read();
var obj = serializer.UnpackFrom(unpacker);
obj = msgPackType.Convert(obj);
return obj;
}
catch (Exception ex)
{
return HandleException(ex, type);
}
}
/// <summary>
/// MsgPack throws an exception for empty DTO's - normalizing the behavior to
/// follow other types and return an empty instance.
/// </summary>
/// <param name="ex"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object HandleException(Exception ex, Type type)
{
if (ex is SerializationException
&& ex.Message.Contains("does not have any serializable fields nor properties"))
return type.CreateInstance();
throw ex;
}
}
}