使用Json.Net反序列化为DataSet时的ArgumentOutOfRange异常

时间:2014-05-09 20:45:04

标签: json vb.net json.net

我在名为strJSON的变量中有以下JSON字符串。

{
   "results":[
      {
         "templateName":"HUD Section 8",
         "userID":"2",
         "mobileObjectId":"4582",
         "source":"M",
         "inspectionType":"A",
         "notes":"Window in bedroom needs repair.",
         "agencyID":"",
         "requestDate":"2014-05-09 00:00:00",
         "agencyName":"",
         "inspectionTimeBegun":"2014-05-09 14:00:17",
         "inspectionDate":"2014-05-09 14:30:00",
         "inspectionID":135,
         "inspectionTimeComplete":"2014-05-09 14:29:25",
         "summaryDecision":"F",
         "createdAt":"2014-05-09T18:29:35.050Z",
         "updatedAt":"2014-05-09T18:29:35.050Z",
         "objectId":"1FgtD6WT8Y",
         "ACL":{
            "*":{
               "read":true
            },
            "cryZoU5gXJ":{
               "write":true,
               "read":true
            }
         }
      }
   ]
}

当我拨打以下代码行时......

ds = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataSet)(strJSON)

我收到一条消息,说明“指定的参数超出了有效值范围”

使用以下对Parse.com的REST API调用创建JSON字符串。

strJSON = http.QuickGetStr(strURL)

我在其他地方成功使用了这个,虽然Parse类更简单,但是我仔细检查了这个JSON字符串并且看不出任何错误。

关于可能导致此错误的任何想法?

2 个答案:

答案 0 :(得分:1)

为了让Json.Net反序列化为DataSet,JSON必须采用特定格式,如this answer中所述。您的JSON很接近,但问题是ACL对象。 Json.Net 5.0使用的DataTableConverter要求表中的所有列都是简单的数据类型,否则会抛出ArgumentOutOfRangeExceptionsource)。除了简单类型之外,Json.Net 6.0还支持嵌套数据表和数组,但您的ACL数据仍然不符合允许将其正确反序列化为DataSet的所需格式。你有几个不同的选择来解决这个问题:

更改JSON

如果您控制JSON的格式(即它不是来自第三方),您可以更改它,以便Json.Net 6.0能够将其反序列化为DataSet。以下是它需要的工作方式:

{
    "results": [
        {
            "templateName": "HUD Section 8",
            "userID": "2",
            "mobileObjectId": "4582",
            "source": "M",
            "inspectionType": "A",
            "notes": "Window in bedroom needs repair.",
            "agencyID": "",
            "requestDate": "2014-05-09 00:00:00",
            "agencyName": "",
            "inspectionTimeBegun": "2014-05-09 14:00:17",
            "inspectionDate": "2014-05-09 14:30:00",
            "inspectionID": 135,
            "inspectionTimeComplete": "2014-05-09 14:29:25",
            "summaryDecision": "F",
            "createdAt": "2014-05-09T18:29:35.050Z",
            "updatedAt": "2014-05-09T18:29:35.050Z",
            "objectId": "1FgtD6WT8Y",
            "ACL": [
                {
                    "user": "*",
                    "read": true,
                    "write": false
                },
                {
                    "user": "cryZoU5gXJ",
                    "read": true,
                    "write": true
                }
            ]
        }
    ]
}

使用此格式,ACL表的results列将包含具有各个ACL行的嵌套DataTable,每行包含三列user,{ {1}}和read

反序列化为强类型类

您可以反序列化为一组强类型类,而不是反序列化为write。这种方法的优点是一切都是易于使用的形式。缺点是在创建类之前需要知道JSON中的内容。

您可以使用第三方工具(如json2csharp.com)来帮助从JSON示例中生成类,如另一个答案(现已删除)中所建议的那样,但请注意,这不是万无一失的(并且它不会#39;做VB)。有时您需要手动干预和编辑类。例如,如果在您的问题中从JSON生成类,您会注意到它为每个ACL实例创建了一个固定类。除非您的ACL集合始终只有两个项目,一个名为DataSet,另一个名为Everyone,否则这将无效。我认为ACL的集合更有可能是可变的,因此对这些使用CryZoU5gXJ是有意义的。以下是我建议的课程:

Dictionary

有了这个类结构,你可以像这样反序列化:

Class RootObject
    Public Property results As List(Of Result)
End Class

Class Result
    Public Property templateName As String
    Public Property userID As String
    Public Property mobileObjectId As String
    Public Property source As String
    Public Property inspectionType As String
    Public Property notes As String
    Public Property agencyID As String
    Public Property requestDate As String
    Public Property agencyName As String
    Public Property inspectionTimeBegun As String
    Public Property inspectionDate As String
    Public Property inspectionID As Integer
    Public Property inspectionTimeComplete As String
    Public Property summaryDecision As String
    Public Property createdAt As String
    Public Property updatedAt As String
    Public Property objectId As String
    Public Property ACL As Dictionary(Of String, ACL)
End Class

Class ACL
    Public Property read As Boolean
    Public Property write As Boolean
End Class

对于ACL,每个字典条目的键将是用户ID(或示例中的Dim root As RootObject = JsonConvert.DeserializeObject(Of RootObject)(strJSON) )。如果您实际上并不关心ACL,则可以省略*类中的ACL属性。默认情况下,Json.Net将跳过JSON中存在但在类中不存在的属性。

使用LINQ-to-JSON API解析JSON

使用Json.Net,总有不止一种方法可以给猫皮肤涂抹。当您正在解析的JSON变化很大和/或您不想创建用于接收数据的类时,Json.Net的LINQ-to-JSON API会非常闪耀。您可以将任何有效的JSON反序列化为JToken对象的层次结构,然后根据需要将它们分开。例如,如果您只需要从每个结果中选择一些信息,则可以执行以下操作:

Result

您可以使用相同的方法从JSON手动构建Dim token As JToken = JToken.Parse(json) For Each result As JObject In token("results").Children(Of JObject)() Console.WriteLine("userID: " + result("userID").ToString()) Console.WriteLine("templateName: " + result("templateName").ToString()) Console.WriteLine("inspectionID: " + result("inspectionID").ToString()) Console.WriteLine("inspectionType: " + result("inspectionType").ToString()) Console.WriteLine("inspectionDate: " + result("inspectionDate").ToString()) Console.WriteLine("summaryDecision: " + result("summaryDecision").ToString()) Console.WriteLine("notes: " + result("notes").ToString()) Next 。这是一个通用函数,它将JSON反序列化为DataSet但忽略任何复杂对象(例如ACL)而不是抛出异常:

DataSet

当然,如果您需要ACL,则需要自定义此方法以将该数据转换为代码可以使用的表单。我会把那部分留给你。

答案 1 :(得分:0)

如果符合某个标准,Json.Net将仅直接解析为DataSet。请参阅this answer了解所需的布局。

但是,您可以反序列化为XML文档,并使用DataSet对象的ReadXml方法为您加载它。有关如何执行此操作的详细信息,请参阅this question

(对于数据集结构详细信息,HT到Brian Rogers