我的应用程序正在使用API,我正在尝试反序列化返回的图像数据。数据格式如下:
{
"images":{
"totalCount":4,
"0":{
"url":"file1.jpg"
},
"1":{
"url":"file2.jpg"
},
"2":{
"url":"file3.jpg"
},
"3":{
"url":"file4.jpg"
}
}
}
我有这些模型类:
public class MyViewModel
{
[JsonProperty("images")]
public ImagesViewModel Images { get; set; }
}
public class ImagesViewModel
{
[JsonProperty("totalCount")]
public int TotalCount { get; set; }
public Dictionary<string, ImageViewModel> ListImages { get; set; }
}
public class ImageViewModel
{
[JsonProperty("url")]
public string Url { get; set; }
}
图像集合并非真正的集合,出于某种原因,它只是每个图像的新属性。我试图反序列化我的对象,如:
... // create HttpClient object, add headers and such
System.Net.Http.HttpResponseMessage response = await
client.GetAsync(endpointUrl);
var jsonString = response.Content.ReadAsStringAsync();
MyViewModel model =
JsonConvert.DeserializeObject<MyViewModel>(jsonString.Result);
我恢复totalCount
属性就好了,但图像集合又回来了。
有没有办法让我更改我的视图模型,以便我可以正确反序列化json?
答案 0 :(得分:3)
鉴于JSON的格式,您将不得不走很长的路线并尝试使用JObjects
反序列化
//using Newtonsoft.Json.Linq
var jObject = JObject.Parse(jsonString);
var images = jObject.Property("images").Value<JObject>(); ;
var viewModel = new MyViewModel {
Images = new ImagesViewModel {
TotalCount = images.Property("totalCount").Value<int>(),
ListImages = images.Properties().Skip(1).ToDictionary(p => p.Name, p => p.Value<ImageViewModel>())
}
};
更进一步,使用JsonConverter
转换有效负载本身实际上也很有效,因为我们现在知道如何转换它。
public class MyViewModelConverter : JsonConverter {
public override bool CanConvert(Type objectType) {
return objectType == typeof(MyViewModel);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var jObject = JObject.Load(reader);//<-- Note the use of Load() instead of Parse()
var images = jObject.Property("images").Value<JObject>(); ;
var model = new MyViewModel {
Images = new ImagesViewModel {
TotalCount = images.Property("totalCount").Value<int>(),
ListImages = images.Properties().Skip(1).ToDictionary(p => p.Name, p => p.Value<ImageViewModel>())
}
};
return model;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
throw new NotImplementedException();
}
}
并装饰课程本身
[JsonConverter(typeof(MyViewModelConverter))]
public class MyViewModel {
[JsonProperty("images")]
public ImagesViewModel Images { get; set; }
}
反序列化现在就像你打算在
之前做的那样var jsonString = await response.Content.ReadAsStringAsync();
MyViewModel model = JsonConvert.DeserializeObject<MyViewModel>(jsonString);
答案 1 :(得分:0)
.NET Abhors动态类型。它们在编译时面对固体类型检查。话虽如此,有人支持它:
由于示例数据基本上只是一个图像数组,因此任何集合都可以处理此输入。
如果你甚至无法定义类型(你可能有一个图像数组和一个字符串),唯一的方法是ExpandoObject。它专门用于处理此类案件。它基本上是一个带有一些Syntax Sugar的List [string,object],但它也包含了Property Change Notifications等功能。
答案 2 :(得分:0)
听起来像是自定义转换器的工作!
自定义转换器将允许您提供自己的逻辑以反序列化特定类型。如果期望在json中找到并调用适当的转换器,Newtonsoft使用目标类来计算类型。
class ImagesViewModelConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ImagesViewModel);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
assertToken(JsonToken.StartObject);
var obj = new ImagesViewModel()
{
ListImages = new Dictionary<string, ImageViewModel>()
};
while (reader.Read() && reader.TokenType != JsonToken.EndObject)
{
assertToken(JsonToken.PropertyName);
var propName = (string)reader.Value;
if (propName.Equals(nameof(ImagesViewModel.TotalCount), StringComparison.InvariantCultureIgnoreCase))
{
reader.Read();
assertToken(JsonToken.Integer);
obj.TotalCount = (int)((Int64)reader.Value);
continue;
}
reader.Read();
var image = serializer.Deserialize<ImageViewModel>(reader); // you can still use normal json deseralization inside a converter
obj.ListImages.Add(propName, image);
}
return obj;
void assertToken(JsonToken token)
{
if (reader.TokenType != token)
throw new Exception(); // might wanna add detailed errors
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException(); // implement if needed
}
}
然后:
var settings = new JsonSerializerSettings()
{
Converters = new[] { new ImagesViewModelConverter() }
};
var obj = JsonConvert.DeserializeObject<MyViewModel>(jsonString, settings);
});
您甚至可以更改类更容易处理,因为它们不再需要完全匹配json。例如,您可以用数组替换dict并让转换器按顺序填充它。