缺少属性名称时的 JSON 反序列化错误



我正在尝试使用外部Web服务,并且正在使用.NET Core和Flurl框架。我从服务中得到如下回复:

[
"Successful Request: 96 Results",
[
{
"eventdate":"2019-10-18",
"name":"",
"url":"",
"info":"",
"showtime":null,
"url_tix":"",
"event_owner":"xxx",
"follow_url":"xxx",
"event_image":"xxx",
"venue":"xxx",
"city":"xxx",
"country":"xxx",
"state":""
}
]
]

我有一个 C# 实体定义,如下所示:

public class ServiceResponce
{
public Event[] Events { get; set; }
}
public class Event
{
[JsonProperty("eventdate")]
public DateTimeOffset Eventdate { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("info")]
public string Info { get; set; }
[JsonProperty("showtime")]
public object Showtime { get; set; }
[JsonProperty("url_tix")]
public object UrlTix { get; set; }
[JsonProperty("event_owner")]
public string EventOwner { get; set; }
[JsonProperty("follow_url")]
public Uri FollowUrl { get; set; }
[JsonProperty("event_image")]
public object EventImage { get; set; }
[JsonProperty("venue")]
public string Venue { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("state")]
public string State { get; set; }
}

当我尝试调用 Flurl 方法来使用 Web 服务时,如下所示:

var result = await serviceUrl.GetJsonAsync<ServiceResponce>();

我收到下面提到的错误:

无法将当前 JSON 数组(例如 [1,2,3](反序列化为类型 "xxx.ServiceResponce",因为该类型需要一个 JSON 对象(例如 {"名称":"值"}(以正确反序列化。要修复此错误 将 JSON 更改为 JSON 对象(例如 {"name":"value"}( 或更改 反序列化类型为数组或实现集合的类型 接口(例如ICollection,IList(像列表一样,可以是 从 JSON 数组反序列化。也可以添加 JsonArrayAttribute 到类型以强制它从 JSON 数组反序列化。路径 '', 第 1 行,位置 1。

你有什么解决方案吗?随时欢迎任何帮助。

这里的问题是 JSON 响应实际上是一个混合类型的数组。 数组的第一个元素是字符串,第二个元素是事件对象的数组。 您将需要一个自定义JsonConverter来反序列化此 JSON。

以下是转换器所需的代码:

class ServiceResponceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(ServiceResponce));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray ja = JArray.Load(reader);
ServiceResponce resp = new ServiceResponce();
resp.Events = ja[1].ToObject<Event[]>(serializer);
return resp;
}
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

然后,将[JsonConverter]属性添加到ServiceResponce类以将其绑定到转换器:

[JsonConverter(typeof(ServiceResponceConverter))]
public class ServiceResponce
{
public Event[] Events { get; set; }
}

现在您可以正常反序列化为ServiceResponce类,它将正常工作。

可选:如果还想从响应中捕获"Successful Request: 96 Results"字符串,请添加

public string ResultString { get; set; }

ServiceResponce类,并将以下行添加到转换器的ReadJson方法中:

resp.ResultString = (string)ja[0];

在这里工作演示:https://dotnetfiddle.net/opPUmX

我认为问题出在 Json 对象中,我已经用"Newtonsoft.Json"生成了一个类,如果你可以尝试以下代码:

// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using MyNameSpace;
//
//    var event = Event.FromJson(jsonString);
namespace MyNameSpace
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class EventClass
{
[JsonProperty("eventdate")]
public DateTimeOffset Eventdate { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("info")]
public string Info { get; set; }
[JsonProperty("showtime")]
public object Showtime { get; set; }
[JsonProperty("url_tix")]
public string UrlTix { get; set; }
[JsonProperty("event_owner")]
public string EventOwner { get; set; }
[JsonProperty("follow_url")]
public string FollowUrl { get; set; }
[JsonProperty("event_image")]
public string EventImage { get; set; }
[JsonProperty("venue")]
public string Venue { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("state")]
public string State { get; set; }
}
public partial struct EventUnion
{
public EventClass[] EventClassArray;
public string String;
public static implicit operator EventUnion(EventClass[] EventClassArray) => new EventUnion { EventClassArray = EventClassArray };
public static implicit operator EventUnion(string String) => new EventUnion { String = String };
}
public class Event
{
public static EventUnion[] FromJson(string json) => JsonConvert.DeserializeObject<EventUnion[]>(json, MyNameSpace.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this EventUnion[] self) => JsonConvert.SerializeObject(self, MyNameSpace.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
EventUnionConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class EventUnionConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(EventUnion) || t == typeof(EventUnion?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
switch (reader.TokenType)
{
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new EventUnion { String = stringValue };
case JsonToken.StartArray:
var arrayValue = serializer.Deserialize<EventClass[]>(reader);
return new EventUnion { EventClassArray = arrayValue };
}
throw new Exception("Cannot unmarshal type EventUnion");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
var value = (EventUnion)untypedValue;
if (value.String != null)
{
serializer.Serialize(writer, value.String);
return;
}
if (value.EventClassArray != null)
{
serializer.Serialize(writer, value.EventClassArray);
return;
}
throw new Exception("Cannot marshal type EventUnion");
}
public static readonly EventUnionConverter Singleton = new EventUnionConverter();
}
}

最新更新