【问题标题】:DataContractJsonSerializer doesn't work with formatted JSON?DataContractJsonSerializer 不适用于格式化的 JSON?
【发布时间】:2011-04-28 20:39:28
【问题描述】:

当使用DataContractJsonSerializer 反序列化 JSON 时,如果输入中有标签(格式化的 JSON),则序列化程序会抛出异常(如下所示)。如果我用“”替换所有空格、制表符和换行符,序列化程序就可以很好地反序列化它。

怎么了?

异常

System.MemberAccessException: Cannot create an abstract class.
at System.Runtime.Serialization.FormatterServices.nativeGetUninitializedObject(RuntimeType type) 
at System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type) 
at System.Runtime.Serialization.XmlFormatReaderGenerator.UnsafeGetUninitializedObject(Int32 id) 
at ReadBaseSearchElementFromJson(XmlReaderDelegator , XmlObjectSerializerReadContextComplexJson , XmlDictionaryString , XmlDictionaryString[] ) 
at System.Runtime.Serialization.Json.JsonClassDataContract.ReadJsonValueCore(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.JsonDataContract.ReadJsonValue(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.XmlObjectSerializerReadContextComplexJson.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) 
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract) 
at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns) 
at ReadSearchElementsFromJson(XmlReaderDelegator , XmlObjectSerializerReadContextComplexJson , XmlDictionaryString , XmlDictionaryString , CollectionDataContract ) 
at System.Runtime.Serialization.Json.JsonCollectionDataContract.ReadJsonValueCore(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.JsonDataContract.ReadJsonValue(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.XmlObjectSerializerReadContextComplexJson.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) 
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract) 
at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, String name, String ns) 
at ReadSearchGroupFromJson(XmlReaderDelegator , XmlObjectSerializerReadContextComplexJson , XmlDictionaryString , XmlDictionaryString[] ) 
at System.Runtime.Serialization.Json.JsonClassDataContract.ReadJsonValueCore(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.JsonDataContract.ReadJsonValue(XmlReaderDelegator jsonReader, XmlObjectSerializerReadContextComplexJson context) 
at System.Runtime.Serialization.Json.XmlObjectSerializerReadContextComplexJson.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) 
at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract) 
at System.Runtime.Serialization.XmlObjectSerializerReadContextComplex.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns) 
at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName) 
at System.Runtime.Serialization.XmlObjectSerializer.InternalReadObject(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver) 
at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver) 
at System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(XmlDictionaryReader reader) 
at System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(Stream stream)

格式化的 JSON

这个反序列化,抛出上面的异常。

{
    "Mode":"And",
    "Elements":
    [
        {
            "Name":"ID",
            "Operator":"Equal",
            "Value":"3"
        }
    ]
}

非格式化 JSON

确实反序列化。

{"Mode":"And","Elements":[{"Name":"ID","Operator":"Equal","Value":"3"}]}

更新

我已经提交了一个 sample solution,它显示了这个问题。

【问题讨论】:

  • 你有没有找到解决这个问题的方法?因为我目前面临同样的问题。
  • 我想出的唯一解决方案是用空替换空格和换行符。我知道,这不是一个真正的解决方案,但就我而言,它可以正常工作。如果您想出更好的方法,请告诉我!
  • @JoshM。请注意,我在 "__type" 之前删除空格的答案允许您保留几乎所有格式。如果这符合您的需求,请考虑接受。

标签: c# .net wcf json


【解决方案1】:

您的大多数格式实际上都很好。 {"__type" 之间不能有任何空格。

查看之前的回答:JSON deseralization to abstract list using DataContractJsonSerializer

例如,您的示例代码正在尝试反序列化此 JSON 字符串:

"{\r\n\t\"Mode\":\"And\",\r\n\t\"Elements\":\r\n\t[\r\n\t\t{\r\n\t\t\t\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\"Name\":\"LastName\",\r\n\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\"Value\":\"Smith\"\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"__type\":\"SearchGroup:#JsonTest.Search\",\r\n\t\t\t\"Mode\":\"Or\",\r\n\t\t\t\"Elements\":\r\n\t\t\t[\r\n\t\t\t\t{\r\n\t\t\t\t\t\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\t\t\"Name\":\"FirstName\",\r\n\t\t\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\t\t\"Value\":\"Tim\"\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\t\t\"Name\":\"FirstName\",\r\n\t\t\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\t\t\"Value\":\"Tom\"\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n}"

格式化:

{
    "Mode":"And",
    "Elements":
    [
        {
            "__type":"SearchParameter:#JsonTest.Search",
            "Name":"LastName",
            "Operator":"Equal",
            "Value":"Smith"
        },
        {
            "__type":"SearchGroup:#JsonTest.Search",
            "Mode":"Or",
            "Elements":
            [
                {
                    "__type":"SearchParameter:#JsonTest.Search",
                    "Name":"FirstName",
                    "Operator":"Equal",
                    "Value":"Tim"
                },
                {
                    "__type":"SearchParameter:#JsonTest.Search",
                    "Name":"FirstName",
                    "Operator":"Equal",
                    "Value":"Tom"
                }
            ]
        }
    ]
}

改成这样,错误就消失了:

"{\r\n\t\"Mode\":\"And\",\r\n\t\"Elements\":\r\n\t[\r\n\t\t{\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\"Name\":\"LastName\",\r\n\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\"Value\":\"Smith\"\r\n\t\t},\r\n\t\t{\"__type\":\"SearchGroup:#JsonTest.Search\",\r\n\t\t\t\"Mode\":\"Or\",\r\n\t\t\t\"Elements\":\r\n\t\t\t[\r\n\t\t\t\t{\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\t\t\"Name\":\"FirstName\",\r\n\t\t\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\t\t\"Value\":\"Tim\"\r\n\t\t\t\t},\r\n\t\t\t\t{\"__type\":\"SearchParameter:#JsonTest.Search\",\r\n\t\t\t\t\t\"Name\":\"FirstName\",\r\n\t\t\t\t\t\"Operator\":\"Equal\",\r\n\t\t\t\t\t\"Value\":\"Tom\"\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n}"

格式化:

{
    "Mode":"And",
    "Elements":
    [
        {"__type":"SearchParameter:#JsonTest.Search",
            "Name":"LastName",
            "Operator":"Equal",
            "Value":"Smith"
        },
        {"__type":"SearchGroup:#JsonTest.Search",
            "Mode":"Or",
            "Elements":
            [
                {"__type":"SearchParameter:#JsonTest.Search",
                    "Name":"FirstName",
                    "Operator":"Equal",
                    "Value":"Tim"
                },
                {"__type":"SearchParameter:#JsonTest.Search",
                    "Name":"FirstName",
                    "Operator":"Equal",
                    "Value":"Tom"
                }
            ]
        }
    ]
}

【讨论】:

  • 是的 - 答案是不使用任何空格。这很烦人!对我来说似乎是一个错误。那好吧。也许 WebAPI 处理得更好。
  • 这太荒谬了。为什么我们不能在 JSON 对象中使用空格?看起来 DataContractJsonSerializer 根本不是好选择。
  • @MilesChen 好吧,我相信 most 空格是可以的,只是不要紧接在特殊的“__type”属性之前。 (这似乎仍然是一个有点愚蠢的要求,但不是繁重,IMO。)
【解决方案2】:

很奇怪。您可能想尝试 JSON.NET,这是一个很好的 JSON 序列化和反序列化库。我最近在一个项目中使用它,它在 DataContractJsonSerializer 失败的情况下工作。

您可以在http://json.codeplex.com/找到它

【讨论】:

  • 感谢 Roy,我更愿意坚持使用框架程序集,因为我所做的并不那么复杂并且“应该”工作。我希望我只是错过了一些东西。
  • 使用现成的、现有的开源解决方案比花费数小时试图围绕它硬塞.NET Framework 不是更好吗?只是我的 2 美分...
  • 当然,它可以——如果框架根本不能做我想要的——但我觉得这只是我缺少的东西。
【解决方案3】:

这很奇怪,因为以下内容对我很有用:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

public class SomeModel
{
    public string Mode { get; set; }
    public IEnumerable<Element> Elements { get; set; }
}

public class Element
{
    public string Name { get; set; }
    public string Operator { get; set; }
    public string Value { get; set; }
}

class Program
{
    static void Main()
    {
        var json =
@"{
    ""Mode"":""And"",
    ""Elements"":
    [
        {
            ""Name"":""ID"",
            ""Operator"":""Equal"",
            ""Value"":""3""
        }
    ]
}";
        var serializer = new DataContractJsonSerializer(typeof(SomeModel));
        using (var stream = new MemoryStream(Encoding.Default.GetBytes(json)))
        {
            var model = (SomeModel)serializer.ReadObject(stream);
            Console.WriteLine(model.Mode);
            foreach (var element in model.Elements)
            {
                Console.WriteLine(element.Name);
                Console.WriteLine(element.Operator);
                Console.WriteLine(element.Value);
            }
        }
    }
}

【讨论】:

  • 谢谢。在我的例子中,“SomeModel”和“Element”都派生自一个基本类型。我现在要发布一个代码示例。
  • @Josh M.,是的,在提出问题时总是发布一些允许重现问题的代码会很好。
  • 我明白这一点,我尝试发布重要的代码,但有时以清晰的方式发布太多了。这就是为什么我创建了一个示例项目并将其附加到我的问题中。我知道这不是普遍接受的方法,但对于依赖于多个类的问题,这是传达问题的唯一明确方法。
  • @Josh M.,这就是为什么遇到问题的第一步是尝试将其隔离到易于重现的应用程序中的原因。顺便说一句,如果您养成始终这样做的习惯,您会发现您不再需要在 StackOverflow 上提问,因为您将自己解决问题:-)
  • 在我花了几个小时试图解决问题之后,在 SO 上发帖是我的最后选择。因此,隔离问题并不总是能让我在没有额外一双眼睛的情况下解决它。我不是在寻找有人在这里“谷歌”为我提供答案(就像其他人倾向于做的那样),这真是令人困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-28
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 2020-06-29
相关资源
最近更新 更多