Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit e232b29

Browse files
committed
Fix interfaces deserialization on .NET Core
1 parent e0e7cfe commit e232b29

11 files changed

+188
-150
lines changed
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#if !(XBOX || SL5 || NETFX_CORE || WP || PCL || __IOS__)
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Reflection.Emit;
7+
8+
namespace ServiceStack
9+
{
10+
public static class DynamicProxy
11+
{
12+
public static T GetInstanceFor<T>()
13+
{
14+
return (T)GetInstanceFor(typeof(T));
15+
}
16+
17+
static readonly ModuleBuilder ModuleBuilder;
18+
static readonly AssemblyBuilder DynamicAssembly;
19+
static readonly Type[] EmptyTypes = new Type[0];
20+
21+
public static object GetInstanceFor(Type targetType)
22+
{
23+
lock (DynamicAssembly)
24+
{
25+
var constructedType = DynamicAssembly.GetType(ProxyName(targetType)) ?? GetConstructedType(targetType);
26+
var instance = Activator.CreateInstance(constructedType);
27+
return instance;
28+
}
29+
}
30+
31+
static string ProxyName(Type targetType)
32+
{
33+
return targetType.Name + "Proxy";
34+
}
35+
36+
static DynamicProxy()
37+
{
38+
var assemblyName = new AssemblyName("DynImpl");
39+
#if NETSTANDARD
40+
DynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
41+
#else
42+
DynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
43+
#endif
44+
ModuleBuilder = DynamicAssembly.DefineDynamicModule("DynImplModule");
45+
}
46+
47+
static Type GetConstructedType(Type targetType)
48+
{
49+
var typeBuilder = ModuleBuilder.DefineType(targetType.Name + "Proxy", TypeAttributes.Public);
50+
51+
var ctorBuilder = typeBuilder.DefineConstructor(
52+
MethodAttributes.Public,
53+
CallingConventions.Standard,
54+
new Type[] { });
55+
var ilGenerator = ctorBuilder.GetILGenerator();
56+
ilGenerator.Emit(OpCodes.Ret);
57+
58+
IncludeType(targetType, typeBuilder);
59+
60+
foreach (var face in targetType.GetTypeInterfaces())
61+
IncludeType(face, typeBuilder);
62+
63+
#if NETSTANDARD
64+
return typeBuilder.CreateTypeInfo().AsType();
65+
#else
66+
return typeBuilder.CreateType();
67+
#endif
68+
}
69+
70+
static void IncludeType(Type typeOfT, TypeBuilder typeBuilder)
71+
{
72+
var methodInfos = typeOfT.GetMethodInfos();
73+
foreach (var methodInfo in methodInfos)
74+
{
75+
if (methodInfo.Name.StartsWith("set_", StringComparison.Ordinal)) continue; // we always add a set for a get.
76+
77+
if (methodInfo.Name.StartsWith("get_", StringComparison.Ordinal))
78+
{
79+
BindProperty(typeBuilder, methodInfo);
80+
}
81+
else
82+
{
83+
BindMethod(typeBuilder, methodInfo);
84+
}
85+
}
86+
87+
typeBuilder.AddInterfaceImplementation(typeOfT);
88+
}
89+
90+
static void BindMethod(TypeBuilder typeBuilder, MethodInfo methodInfo)
91+
{
92+
var methodBuilder = typeBuilder.DefineMethod(
93+
methodInfo.Name,
94+
MethodAttributes.Public | MethodAttributes.Virtual,
95+
methodInfo.ReturnType,
96+
methodInfo.GetParameters().Select(p => p.GetType()).ToArray()
97+
);
98+
var methodILGen = methodBuilder.GetILGenerator();
99+
if (methodInfo.ReturnType == typeof(void))
100+
{
101+
methodILGen.Emit(OpCodes.Ret);
102+
}
103+
else
104+
{
105+
if (methodInfo.ReturnType.IsValueType() || methodInfo.ReturnType.IsEnum())
106+
{
107+
#if NETSTANDARD
108+
MethodInfo getMethod = typeof(Activator).GetMethod("CreateInstance");
109+
#else
110+
MethodInfo getMethod = typeof(Activator).GetMethod("CreateInstance",
111+
new[] { typeof(Type) });
112+
#endif
113+
LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType);
114+
methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);
115+
methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
116+
methodILGen.Emit(OpCodes.Callvirt, getMethod);
117+
methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
118+
}
119+
else
120+
{
121+
methodILGen.Emit(OpCodes.Ldnull);
122+
}
123+
methodILGen.Emit(OpCodes.Ret);
124+
}
125+
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
126+
}
127+
128+
public static void BindProperty(TypeBuilder typeBuilder, MethodInfo methodInfo)
129+
{
130+
// Backing Field
131+
string propertyName = methodInfo.Name.Replace("get_", "");
132+
Type propertyType = methodInfo.ReturnType;
133+
FieldBuilder backingField = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
134+
135+
//Getter
136+
MethodBuilder backingGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
137+
MethodAttributes.SpecialName | MethodAttributes.Virtual |
138+
MethodAttributes.HideBySig, propertyType, EmptyTypes);
139+
ILGenerator getIl = backingGet.GetILGenerator();
140+
141+
getIl.Emit(OpCodes.Ldarg_0);
142+
getIl.Emit(OpCodes.Ldfld, backingField);
143+
getIl.Emit(OpCodes.Ret);
144+
145+
146+
//Setter
147+
MethodBuilder backingSet = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public |
148+
MethodAttributes.SpecialName | MethodAttributes.Virtual |
149+
MethodAttributes.HideBySig, null, new[] { propertyType });
150+
151+
ILGenerator setIl = backingSet.GetILGenerator();
152+
153+
setIl.Emit(OpCodes.Ldarg_0);
154+
setIl.Emit(OpCodes.Ldarg_1);
155+
setIl.Emit(OpCodes.Stfld, backingField);
156+
setIl.Emit(OpCodes.Ret);
157+
158+
// Property
159+
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
160+
propertyBuilder.SetGetMethod(backingGet);
161+
propertyBuilder.SetSetMethod(backingSet);
162+
}
163+
}
164+
}
165+
#endif

src/ServiceStack.Text/PclExport.Net40.cs

Lines changed: 0 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -989,150 +989,6 @@ public override void VerifyInAssembly(Type accessType, ICollection<string> assem
989989
}
990990
#endif
991991

992-
#if !__IOS__
993-
public static class DynamicProxy
994-
{
995-
public static T GetInstanceFor<T>()
996-
{
997-
return (T)GetInstanceFor(typeof(T));
998-
}
999-
1000-
static readonly ModuleBuilder ModuleBuilder;
1001-
static readonly AssemblyBuilder DynamicAssembly;
1002-
1003-
public static object GetInstanceFor(Type targetType)
1004-
{
1005-
lock (DynamicAssembly)
1006-
{
1007-
var constructedType = DynamicAssembly.GetType(ProxyName(targetType)) ?? GetConstructedType(targetType);
1008-
var instance = Activator.CreateInstance(constructedType);
1009-
return instance;
1010-
}
1011-
}
1012-
1013-
static string ProxyName(Type targetType)
1014-
{
1015-
return targetType.Name + "Proxy";
1016-
}
1017-
1018-
static DynamicProxy()
1019-
{
1020-
var assemblyName = new AssemblyName("DynImpl");
1021-
DynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
1022-
ModuleBuilder = DynamicAssembly.DefineDynamicModule("DynImplModule");
1023-
}
1024-
1025-
static Type GetConstructedType(Type targetType)
1026-
{
1027-
var typeBuilder = ModuleBuilder.DefineType(targetType.Name + "Proxy", TypeAttributes.Public);
1028-
1029-
var ctorBuilder = typeBuilder.DefineConstructor(
1030-
MethodAttributes.Public,
1031-
CallingConventions.Standard,
1032-
new Type[] { });
1033-
var ilGenerator = ctorBuilder.GetILGenerator();
1034-
ilGenerator.Emit(OpCodes.Ret);
1035-
1036-
IncludeType(targetType, typeBuilder);
1037-
1038-
foreach (var face in targetType.GetInterfaces())
1039-
IncludeType(face, typeBuilder);
1040-
1041-
return typeBuilder.CreateType();
1042-
}
1043-
1044-
static void IncludeType(Type typeOfT, TypeBuilder typeBuilder)
1045-
{
1046-
var methodInfos = typeOfT.GetMethods();
1047-
foreach (var methodInfo in methodInfos)
1048-
{
1049-
if (methodInfo.Name.StartsWith("set_", StringComparison.Ordinal)) continue; // we always add a set for a get.
1050-
1051-
if (methodInfo.Name.StartsWith("get_", StringComparison.Ordinal))
1052-
{
1053-
BindProperty(typeBuilder, methodInfo);
1054-
}
1055-
else
1056-
{
1057-
BindMethod(typeBuilder, methodInfo);
1058-
}
1059-
}
1060-
1061-
typeBuilder.AddInterfaceImplementation(typeOfT);
1062-
}
1063-
1064-
static void BindMethod(TypeBuilder typeBuilder, MethodInfo methodInfo)
1065-
{
1066-
var methodBuilder = typeBuilder.DefineMethod(
1067-
methodInfo.Name,
1068-
MethodAttributes.Public | MethodAttributes.Virtual,
1069-
methodInfo.ReturnType,
1070-
methodInfo.GetParameters().Select(p => p.GetType()).ToArray()
1071-
);
1072-
var methodILGen = methodBuilder.GetILGenerator();
1073-
if (methodInfo.ReturnType == typeof(void))
1074-
{
1075-
methodILGen.Emit(OpCodes.Ret);
1076-
}
1077-
else
1078-
{
1079-
if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum)
1080-
{
1081-
MethodInfo getMethod = typeof(Activator).GetMethod("CreateInstance",
1082-
new[] { typeof(Type) });
1083-
LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType);
1084-
methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);
1085-
methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
1086-
methodILGen.Emit(OpCodes.Callvirt, getMethod);
1087-
methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
1088-
}
1089-
else
1090-
{
1091-
methodILGen.Emit(OpCodes.Ldnull);
1092-
}
1093-
methodILGen.Emit(OpCodes.Ret);
1094-
}
1095-
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
1096-
}
1097-
1098-
public static void BindProperty(TypeBuilder typeBuilder, MethodInfo methodInfo)
1099-
{
1100-
// Backing Field
1101-
string propertyName = methodInfo.Name.Replace("get_", "");
1102-
Type propertyType = methodInfo.ReturnType;
1103-
FieldBuilder backingField = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
1104-
1105-
//Getter
1106-
MethodBuilder backingGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
1107-
MethodAttributes.SpecialName | MethodAttributes.Virtual |
1108-
MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
1109-
ILGenerator getIl = backingGet.GetILGenerator();
1110-
1111-
getIl.Emit(OpCodes.Ldarg_0);
1112-
getIl.Emit(OpCodes.Ldfld, backingField);
1113-
getIl.Emit(OpCodes.Ret);
1114-
1115-
1116-
//Setter
1117-
MethodBuilder backingSet = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public |
1118-
MethodAttributes.SpecialName | MethodAttributes.Virtual |
1119-
MethodAttributes.HideBySig, null, new[] { propertyType });
1120-
1121-
ILGenerator setIl = backingSet.GetILGenerator();
1122-
1123-
setIl.Emit(OpCodes.Ldarg_0);
1124-
setIl.Emit(OpCodes.Ldarg_1);
1125-
setIl.Emit(OpCodes.Stfld, backingField);
1126-
setIl.Emit(OpCodes.Ret);
1127-
1128-
// Property
1129-
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
1130-
propertyBuilder.SetGetMethod(backingGet);
1131-
propertyBuilder.SetSetMethod(backingSet);
1132-
}
1133-
}
1134-
#endif
1135-
1136992
internal class SerializerUtils<TSerializer>
1137993
where TSerializer : ITypeSerializer
1138994
{

src/ServiceStack.Text/PclExport.NetStandard.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using ServiceStack.Text.Common;
1212
using ServiceStack.Text.Json;
1313
using System.Globalization;
14+
using System.Reflection.Emit;
1415
#if NETSTANDARD13
1516
using System.Collections.Specialized;
1617
#endif
@@ -170,6 +171,16 @@ public static StringCollection ToStringCollection(List<string> items)
170171
}
171172
#endif
172173

174+
public override Type UseType(Type type)
175+
{
176+
if (type.IsInterface() || type.IsAbstract())
177+
{
178+
return DynamicProxy.GetInstanceFor(type).GetType();
179+
}
180+
return type;
181+
}
182+
183+
173184
public override ParseStringDelegate GetJsReaderParseMethod<TSerializer>(Type type)
174185
{
175186
if (type.AssignableFrom(typeof(System.Dynamic.IDynamicMetaObjectProvider)) ||

src/ServiceStack.Text/ServiceStack.Text.Android.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@
264264
<Compile Include="XmlSerializer.cs">
265265
<SubType>Code</SubType>
266266
</Compile>
267+
<Compile Include="DynamicProxy.cs" />
268+
<Compile Include="PclExport.NetStandard.cs" />
267269
</ItemGroup>
268270
<!--ItemGroup,Content-->
269271
<!--ItemGroup,None-->

src/ServiceStack.Text/ServiceStack.Text.AndroidIndie.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@
262262
<Compile Include="XmlSerializer.cs">
263263
<SubType>Code</SubType>
264264
</Compile>
265+
<Compile Include="DynamicProxy.cs" />
266+
<Compile Include="PclExport.NetStandard.cs" />
265267
</ItemGroup>
266268
<!--ItemGroup,Content-->
267269
<!--ItemGroup,None-->

src/ServiceStack.Text/ServiceStack.Text.PCL.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@
269269
<SubType>Code</SubType>
270270
</Compile>
271271
<Compile Include="ParseAsType.cs" />
272+
<Compile Include="DynamicProxy.cs" />
273+
<Compile Include="PclExport.NetStandard.cs" />
272274
</ItemGroup>
273275
<!--ItemGroup,Content-->
274276
<!--ItemGroup,None-->

src/ServiceStack.Text/ServiceStack.Text.SL5.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@
292292
<SubType>Code</SubType>
293293
</Compile>
294294
<Compile Include="ParseAsType.cs" />
295+
<Compile Include="DynamicProxy.cs" />
296+
<Compile Include="PclExport.NetStandard.cs" />
295297
</ItemGroup>
296298
<!--ItemGroup,Content-->
297299
<!--ItemGroup,None-->

src/ServiceStack.Text/ServiceStack.Text.Signed.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@
324324
<SubType>Code</SubType>
325325
</Compile>
326326
<Compile Include="ParseAsType.cs" />
327+
<Compile Include="DynamicProxy.cs" />
328+
<Compile Include="PclExport.NetStandard.cs" />
327329
</ItemGroup>
328330
<ItemGroup>
329331
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

src/ServiceStack.Text/ServiceStack.Text.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@
318318
<SubType>Code</SubType>
319319
</Compile>
320320
<Compile Include="ParseAsType.cs" />
321+
<Compile Include="DynamicProxy.cs" />
322+
<Compile Include="PclExport.NetStandard.cs" />
321323
</ItemGroup>
322324
<ItemGroup>
323325
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

0 commit comments

Comments
 (0)