Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert JObject to anonymous object

I am trying to pass an object into a web api application. While serializing the object it converts it to a json string. But on the wep api application side, it gets the object parameter as a JObject. This code block is from the web api application;

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

This code generates a JObject but I need an anonymous object. Web api project doesn't knows the types. Any object types can be received.

I need an object like this.

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

ExpandoObject type doesn't meet my requirements so converting to a dynamic type is not a solution for me.

like image 980
Baran Avatar asked Nov 09 '16 13:11

Baran


3 Answers

The closest I can find using Newtonsoft's deserializer is

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

See Deserialize json object into dynamic object using Json.net

Cheers

like image 121
JasonX Avatar answered Oct 08 '22 09:10

JasonX


Json objects can not be fully serialized as an object. If you are using Newtonsoft it converts unknown type to a JObject. In this problem we tried to create unknown type on runtime. In order to do this on the wep api side we have to pass the type detail into the web api application. Json.NET Schema library can serialize a Type to a string. This method helps us to pass the unknown types' schema to the web api application. From the web api side two parameters needed. First parameter is json schema string and the second one is json data string. At this point by the help of json schema string we can generate this type on runtime by using Reflection library. Here is the C# class. But it doesnt works for lists or arrays. In the future I can develop it.

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

The Convert method helps to generate object from json data by the help of json schema. Just using Newtonsoft.Json.JsonConvert.DeserializeObject(json, type) command we can get a real object. It works with Telerik Reporting as a ObjectDataSource.

like image 23
Baran Avatar answered Oct 08 '22 11:10

Baran


Probably too old a conversation now to be useful since JsonConvert.DeserializeAnonymousType exists now but having looked at this post specifically for JObject I came up with a slightly simpler option which someone might in the future want to use :)

I created the extension method below which simply wraps the standard JObject.ToObject method.

 public static T ToAnonymousType<T>(this JObject source, T destinationType)
 {
     return source.ToObject<T>();
 }

This can then be used like this:

JObject myJObject = new JObject(); // Something more exciting probably happens here
var myAnonymousObject = myJObject.ToAnonymousType(new { Id = default(int), Name = default(string) });
like image 45
Baguazhang Avatar answered Oct 08 '22 09:10

Baguazhang