【问题标题】:Convert JObject to anonymous object将 JObject 转换为匿名对象
【发布时间】:2016-11-09 13:14:55
【问题描述】:

我正在尝试将对象传递给 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);

此代码生成一个 JObject,但我需要一个匿名对象。 Web api 项目不知道类型。可以接收任何对象类型。

我需要一个这样的对象。

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

ExpandoObject 类型不符合我的要求,因此转换为动态类型不是我的解决方案。

【问题讨论】:

标签: c# asp.net-web-api reflection json.net deserialization


【解决方案1】:

使用 Newtonsoft 的反序列化器我能找到的最接近的是

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

Deserialize json object into dynamic object using Json.net

干杯

【讨论】:

  • 抱歉,动态类型不是我的解决方案。
  • 我相信您要么必须为 JSON 对象定义一个类,要么动态创建对象类,要么使用动态对象。我可能错了,但我认为没有第四个有用的选项。
【解决方案2】:

Json 对象不能完全序列化为对象。如果您使用 Newtonsoft,它将未知类型转换为 JObject。在这个问题中,我们尝试在运行时创建未知类型。为了在 wep api 端执行此操作,我们必须将类型详细信息传递给 web api 应用程序。 Json.NET Schema 库可以将 Type 序列化为字符串。此方法帮助我们将未知类型的模式传递给 Web api 应用程序。从 web api 端需要两个参数。第一个参数是 json 模式字符串,第二个参数是 json 数据字符串。此时,借助 json 模式字符串,我们可以使用反射库在运行时生成这种类型。这是 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);
    }
}

Convert 方法通过 json 模式帮助从 json 数据生成对象。只需使用 Newtonsoft.Json.JsonConvert.DeserializeObject(json, type) 命令,我们就可以得到一个真实的对象。它与 Telerik Reporting 作为 ObjectDataSource 一起使用。

【讨论】:

    【解决方案3】:

    由于 JsonConvert.DeserializeAnonymousType 现在已经存在,现在的对话可能太旧了,无法使用,但是在专门为 JObject 看过这篇文章后,我想出了一个稍微简单的选项,将来有人可能会想要使用它:)

    我在下面创建了扩展方法,它简单地包装了标准 JObject.ToObject 方法。

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

    然后可以这样使用:

    JObject myJObject = new JObject(); // Something more exciting probably happens here
    var myAnonymousObject = myJObject.ToAnonymousType(new { Id = default(int), Name = default(string) });
    

    【讨论】:

      猜你喜欢
      • 2020-04-18
      • 2016-08-02
      • 1970-01-01
      • 1970-01-01
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多