【问题标题】:JSON deserialization error when property name is missing缺少属性名称时出现 JSON 反序列化错误
【发布时间】:2019-10-14 10:49:50
【问题描述】:

我正在尝试使用外部 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 对象(例如 {"name":"value"}) 正确反序列化。要修复此错误 将 JSON 更改为 JSON 对象(例如 {"name":"value"})或更改 将类型反序列化为数组或实现集合的类型 接口(例如 ICollection、IList),例如 List 可以 从 JSON 数组反序列化。也可以添加 JsonArrayAttribute 强制它从 JSON 数组反序列化的类型。小路 '', 第 1 行,位置 1。

你有什么解决办法吗?欢迎任何帮助。

【问题讨论】:

  • 我只有得到;在属性中,因此也没有序列化:(。添加 Set; 后也进入属性 def,正确序列化。希望对您有所帮助!

标签: c# json .net-core flurl


【解决方案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

【讨论】:

    【解决方案2】:

    我认为问题出在 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();
        }
    }
    

    【讨论】:

    • 感谢您的回答。实际上,我通过使用在线 json to c# object 工具尝试了同样的事情。但我得到了另一个错误。如下所示:将值“成功请求:96 个结果”转换为类型“DataMigration.EventClass”时出错。路径“[0]”,第 1 行,位置 33。
    • 我认为我收到此错误是因为“成功请求:96 个结果”没有属性名称,只有值。问题是我无法触摸服务结果,因为它是外部的。
    猜你喜欢
    • 1970-01-01
    • 2021-06-11
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多