2016-11-09 111 views
0

我試圖將對象傳遞到Web API應用程序。在序列化對象時,它會將其轉換爲json字符串。但是在wep api應用程序端,它將對象參數作爲JObject獲取。 此代碼塊來自web api應用程序;轉換JObject匿名對象

//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); 

此代碼生成一個JObject,但我需要一個匿名對象。 Web api項目不知道類型。任何對象類型都可以被接收。

我需要這樣一個對象。

object anonyObj = new { Prop1 = "Lorem" }; 

ExpandoObject類型不符合我的要求,因此轉換爲動態類型不是我的解決方案。

+0

Telerik報告ObjectDataSource控件需要一個真正的對象,所以我試圖解決這個問題。 – Baran

+1

這將會非常複雜。你可以從http://stackoverflow.com/questions/3862226/how-to-create-dynamically-a-class-in-c或http://stackoverflow.com/questions/606104/how-to-create- linq-expression-tree-to-select-an-anonymous-type/28140345#28140345 – dbc

+1

根據[文檔](http://docs.telerik.com/reporting/objectdatasource),Telerik Reporting ObjectDataSource可以綁定到像DataSet,DataTable,IListSource和IEnumerable等。所以除了嘗試創建匿名對象之外,您還有其他選擇。 –

回答

0

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); 
    } 
} 

轉換方法有助於通過JSON模式的幫助下生成JSON數據對象。只需使用Newtonsoft.Json.JsonConvert.DeserializeObject(json,type)命令,我們就可以得到一個真實的對象。它與Telerik Reporting一起作爲ObjectDataSource工作。

2

我可以找到使用Newtonsoft的解串器最接近的是

dynamic d = JObject.Parse("{a:1000, b:'c', d: [1,2,3]}"); 

Deserialize json object into dynamic object using Json.net

乾杯

+0

對不起,動態類型不適合我。 – Baran

+0

我相信你要麼爲你的JSON對象定義一個類,動態地創建你的對象類,要麼使用動態對象。我可能是錯的,但我不認爲有一個有用的第四選項。 – JasonX