无法反序列化 Zoho Docs API 响应
Can't deserialize Zoho Docs API response
任何人都可以告诉我我在尝试反序列化此 Zoho Docs API 响应时做错了什么吗?
我有一个以“我的文件夹”为根的文件夹结构,然后是其中的“TestFolder”。这是我从 Zoho Docs API:
返回的 JSON 响应
[
{
"FOLDER_NAME": "My Folders",
"SUCCESS": "1",
"SCOPE": "0"
},
[
{
"AUTHOR_ID": "123456",
"FOLDER_ID": "xxx",
"PARENT_FOLDER_ID": "1",
"FOLDER_NAME": "TestFolder",
"LAST_MODIFIED_TIME": "1435875889219",
"ENCFOLDER_NAME": "TestFolder",
"SCOPE": "0",
"AUTHOR_NAME": "John Smith",
"LAST_MODIFIEDBY": "123456",
"IS_SHARED": true,
"LAST_MODIFIED_AUTHOR_NAME": "John Smith"
}
]
]
我试图用这个 class 将响应反序列化到一个文件夹或列表中,但我没有成功:
public class Folder
{
[JsonProperty("FOLDER_NAME")]
public string FolderName { get; set; }
}
无论我尝试将其反序列化为对象还是文件夹列表,我都会从 Json.NET:
收到此错误
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ZohoModels.Folder' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
这里有两个问题:
根容器是数组而不是对象,因此需要反序列化为集合,例如List<Folder>
。
数组包含两个条目:一个 JSON 对象和嵌套的 JSON 数组。 documentation 含糊不清,但看起来这些文件夹是递归的,文件夹数组将包含成对的 folder/child 文件夹数组容器。由于 Json.NET 根据它是否实现 IEnumerable
来决定是否序列化一个 POCO,因此没有一个 class 可以同时从 JSON 数组和 JSON对象。因此,有必要为 List<Folder>
创建自定义 JSON 转换器以跳过数组并将文件夹与其子数组相匹配。
以下 classes 和转换器应该完成这项工作:
public class Folder
{
public Folder() { this.Folders = new List<Folder>(); }
[JsonProperty("FOLDER_NAME")]
public string FolderName { get; set; }
public List<Folder> Folders { get; set; }
}
public class FolderListConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<Folder>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
// Format of a folder list is
// Object with name of folder
// Array of child folders as a folderlist.
var folders = (existingValue as List<Folder> ?? new List<Folder>());
var array = JArray.Load(reader);
foreach (var token in array)
{
switch (token.Type)
{
case JTokenType.Object:
folders.Add(token.ToObject<Folder>(serializer));
break;
case JTokenType.Array:
{
var folder = folders.Last(); // Throws an exception if none read yet.
(folder.Folders = (folder.Folders ?? new List<Folder>())).AddRange(token.ToObject<List<Folder>>(serializer));
}
break;
default:
throw new JsonSerializationException("unknown token " + token.ToString());
}
}
return folders;
}
public override bool CanWrite { get { return false; }}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
并像这样使用它:
var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new FolderListConverter() } };
var folders = JsonConvert.DeserializeObject<List<Folder>>(json, settings);
任何人都可以告诉我我在尝试反序列化此 Zoho Docs API 响应时做错了什么吗?
我有一个以“我的文件夹”为根的文件夹结构,然后是其中的“TestFolder”。这是我从 Zoho Docs API:
返回的 JSON 响应[
{
"FOLDER_NAME": "My Folders",
"SUCCESS": "1",
"SCOPE": "0"
},
[
{
"AUTHOR_ID": "123456",
"FOLDER_ID": "xxx",
"PARENT_FOLDER_ID": "1",
"FOLDER_NAME": "TestFolder",
"LAST_MODIFIED_TIME": "1435875889219",
"ENCFOLDER_NAME": "TestFolder",
"SCOPE": "0",
"AUTHOR_NAME": "John Smith",
"LAST_MODIFIEDBY": "123456",
"IS_SHARED": true,
"LAST_MODIFIED_AUTHOR_NAME": "John Smith"
}
]
]
我试图用这个 class 将响应反序列化到一个文件夹或列表中,但我没有成功:
public class Folder
{
[JsonProperty("FOLDER_NAME")]
public string FolderName { get; set; }
}
无论我尝试将其反序列化为对象还是文件夹列表,我都会从 Json.NET:
收到此错误Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ZohoModels.Folder' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
这里有两个问题:
根容器是数组而不是对象,因此需要反序列化为集合,例如
List<Folder>
。数组包含两个条目:一个 JSON 对象和嵌套的 JSON 数组。 documentation 含糊不清,但看起来这些文件夹是递归的,文件夹数组将包含成对的 folder/child 文件夹数组容器。由于 Json.NET 根据它是否实现
IEnumerable
来决定是否序列化一个 POCO,因此没有一个 class 可以同时从 JSON 数组和 JSON对象。因此,有必要为List<Folder>
创建自定义 JSON 转换器以跳过数组并将文件夹与其子数组相匹配。
以下 classes 和转换器应该完成这项工作:
public class Folder
{
public Folder() { this.Folders = new List<Folder>(); }
[JsonProperty("FOLDER_NAME")]
public string FolderName { get; set; }
public List<Folder> Folders { get; set; }
}
public class FolderListConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<Folder>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
// Format of a folder list is
// Object with name of folder
// Array of child folders as a folderlist.
var folders = (existingValue as List<Folder> ?? new List<Folder>());
var array = JArray.Load(reader);
foreach (var token in array)
{
switch (token.Type)
{
case JTokenType.Object:
folders.Add(token.ToObject<Folder>(serializer));
break;
case JTokenType.Array:
{
var folder = folders.Last(); // Throws an exception if none read yet.
(folder.Folders = (folder.Folders ?? new List<Folder>())).AddRange(token.ToObject<List<Folder>>(serializer));
}
break;
default:
throw new JsonSerializationException("unknown token " + token.ToString());
}
}
return folders;
}
public override bool CanWrite { get { return false; }}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
并像这样使用它:
var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new FolderListConverter() } };
var folders = JsonConvert.DeserializeObject<List<Folder>>(json, settings);