Bar*_*ran 6 c# reflection json.net deserialization asp.net-web-api
我正在尝试将对象传递给 Web api 应用程序。在序列化对象时,它会将其转换为 json 字符串。但是在 wep api 应用程序端,它将对象参数作为 JObject 获取。此代码块来自 web api 应用程序;
//Read web api body content into a string variable
var resultStr = Request.Content.ReadAsStringAsync().Result;
//Convert json string to object with Newtonsoft
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<object>(resultStr);
Run Code Online (Sandbox Code Playgroud)
此代码生成一个 JObject 但我需要一个匿名对象。Web api 项目不知道类型。可以接收任何对象类型。
我需要一个这样的对象。
object anonyObj = new { Prop1 = "Lorem" };
Run Code Online (Sandbox Code Playgroud)
ExpandoObject 类型不符合我的要求,因此转换为动态类型对我来说不是一个解决方案。
Json 对象无法完全序列化为对象。如果您使用 Newtonsoft,它将未知类型转换为 JObject。在这个问题中,我们尝试在运行时创建未知类型。为了在 wep api 端执行此操作,我们必须将类型详细信息传递到 Web api 应用程序中。 Json.NET Schema库可以将 Type 序列化为字符串。此方法帮助我们将未知类型的架构传递给 Web API 应用程序。从 Web api 端需要两个参数。第一个参数是 json 架构字符串,第二个参数是 json 数据字符串。此时,借助 json 模式字符串,我们可以使用 Reflection 库在运行时生成此类型。这是 C# 类。但它不适用于列表或数组。将来我可以开发它。
public class ObjectConverter
{
public static object Convert(string json, JSchema schema)
{
var type = CreateType(schema);
var destObject = Newtonsoft.Json.JsonConvert.DeserializeObject(json, type);
return destObject;
}
private static Type CreateType(JSchema schema)
{
Type result = null;
var typeBuilder = GetTypeBuilder(Guid.NewGuid().ToString());
foreach (var item in schema.Properties)
{
if (item.Value.Type == (Newtonsoft.Json.Schema.JSchemaType.Object | Newtonsoft.Json.Schema.JSchemaType.Null))
{
Type type = CreateType(item.Value);
if (item.Value.Type != null)
{
CreateProperty(typeBuilder, item.Key, type);
}
}
else
{
if (item.Value.Type != null)
{
CreateProperty(typeBuilder, item.Key, ConvertType(item.Value.Type.Value));
}
}
}
result = typeBuilder.CreateType();
return result;
}
private static Type ConvertType(JSchemaType source)
{
Type result = null;
switch (source)
{
case JSchemaType.None:
break;
case JSchemaType.String:
result = typeof(string);
break;
case JSchemaType.Number:
result = typeof(float);
break;
case JSchemaType.Integer:
result = typeof(int);
break;
case JSchemaType.Boolean:
result = typeof(bool);
break;
case JSchemaType.Object:
result = typeof(object);
break;
case JSchemaType.Array:
result = typeof(Array);
break;
case JSchemaType.Null:
result = typeof(Nullable);
break;
case Newtonsoft.Json.Schema.JSchemaType.String | Newtonsoft.Json.Schema.JSchemaType.Null:
result = typeof(string);
break;
default:
break;
}
return result;
}
private static TypeBuilder GetTypeBuilder(string typeSignature)
{
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
Run Code Online (Sandbox Code Playgroud)
Convert 方法有助于借助 json 模式从 json 数据生成对象。只需使用 Newtonsoft.Json.JsonConvert.DeserializeObject(json, type) 命令我们就可以获得一个真实的对象。它作为 ObjectDataSource 与 Telerik Reporting 一起使用。