You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级JsonApiSerializer至1.74版本时自定义转换器失效问题

JsonApiSerializer升级至1.74后自定义转换器失效问题

我在项目中使用JsonApiSerializer,将其从1.3.1版本升级到最新的1.74版本后,自定义转换器无法正确反序列化JSON。转换器的ReadJson方法断点从未命中,反而一直执行CanConvert方法(该方法返回false)。

收到的错误信息:

JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.String' because the type requires a JSON primitive value (e.g. string, number, boolean, null) to deserialize correctly. To fix this error either change the JSON to a JSON primitive value (e.g. string, number, boolean, null) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'data[0].relationships.matches.data[0].type'.

待反序列化的对象

public class PubgPlayer : PubgShardedEntity
{
    [JsonProperty("Name")]
    public string Name { get; set; }

    [JsonProperty]
    public DateTime CreatedAt { get; set; }

    [JsonProperty]
    public string PatchVersion { get; set; }

    [JsonProperty]
    public string TitleId { get; set; }

    [JsonProperty("matches")]        
    [JsonConverter(typeof(RelationshipIdConverter))]
    public IEnumerable<string> MatchIds { get; set; }        
}

自定义转换器代码

public class RelationshipIdConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => false;
    public override bool CanWrite => false;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        //if the reader is not reading a relationship object just deserialize as normal.
        //This allows us to serialize and deserialize multiple times after converting from the Json-API format
        if (reader.TokenType != JsonToken.StartObject)
            return serializer.Deserialize(reader, objectType);

        JToken jt = JToken.Load(reader);

        var dataToken = jt.SelectToken("data");
        
        if (objectType == typeof(string))
            return dataToken["id"].ToString();
        
        return dataToken.Select(x => (string)x["id"]).ToList();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }
}

示例JSON

{
   "data":[
      {
         "type":"player",
         "id":"account.f96f1d482a5d4a21a4135f598f5a5c6a",
         "attributes":{
            "name":"Nomad_o7",
            "stats":null,
            "titleId":"pubg",
            "shardId":"steam",
            "patchVersion":""
         },
         "relationships":{
            "assets":{
               "data":[
                  
               ]
            },
            "matches":{
               "data":[
                  {
                     "type":"match",
                     "id":"e14ca749-3c19-49dd-9486-03de90669fa3"
                  },
                  {
                     "type":"match",
                     "id":"73dbca3e-eeee-44eb-9c43-3f71df0e02ae"
                  },
                  {
                     "type":"match",
                     "id":"e9f80ed0-1e78-4500-950f-174028fb73cc"
                  }
               ]
            }
         },
         "links":{
            "self":"https://api.pubg.com/shards/steam/players/account.f96f1d482a5d4a21a4135f598f5a5c6a",
            "schema":""
         }
      },
      {
         "type":"player",
         "id":"account.82bad0072f31455d8d9f8d834da2f2f3",
         "attributes":{
            "name":"TGLTN",
            "stats":null,
            "titleId":"pubg",
            "shardId":"steam",
            "patchVersion":""
         },
         "relationships":{
            "assets":{
               "data":[
                  
               ]
            },
            "matches":{
               "data":[
                  {
                     "type":"match",
                     "id":"4a6f064e-c292-4e9b-a3a6-bbaed891ce27"
                  },
                  {
                     "type":"match",
                     "id":"efd9434c-4116-4b56-815d-e30903b37c23"
                  },
                  {
                     "type":"match",
                     "id":"c1e56bff-db4c-470b-bb44-3c2068e33245"
                  },
                  {
                     "type":"match",
                     "id":"44d27efc-3cc6-4935-8bbe-702e4da44744"
                  },
                  {
                     "type":"match",
                     "id":"be3ebed3-9183-47f1-b4b0-40a2229dd5ff"
                  }                 
               ]
            }
         },
         "links":{
            "self":"https://api.pubg.com/shards/steam/players/account.82bad0072f31455d8d9f8d834da2f2f3",
            "schema":""
         }
      }
   ],
   "links":{
      "self":"https://api.pubg.com/shards/steam/players?filter[playerNames]=Nomad_o7,TGLTN"
   },
   "meta":{
      
   }
}

问题原因及解决方法

核心问题

JsonApiSerializer 1.74版本对转换器的处理逻辑有变更:当转换器的CanConvert返回false时,即便通过[JsonConverter]特性直接指定了转换器,框架也会跳过它,转而使用默认序列化逻辑,从而引发错误。

修复步骤

  1. 修正CanConvert方法:让它返回true,或者精准匹配需要处理的类型:
public override bool CanConvert(Type objectType)
{
    return objectType == typeof(string) || typeof(IEnumerable<string>).IsAssignableFrom(objectType);
}

这样框架能明确识别该转换器的处理范围,确保ReadJson方法被调用。

  1. 适配新版本内置逻辑:升级后的JsonApiSerializer已内置JSON:API关系处理能力,可直接用内置特性替代自定义转换器:
[JsonProperty("matches")]
[Relationship(IdOnly = true)]
public IEnumerable<string> MatchIds { get; set; }

若必须保留自定义转换器,需确保其逻辑与新版本序列化流程兼容,比如增加空值判断避免异常。

  1. 验证特性配置:确认[JsonConverter]特性正确应用在目标属性上,且未被全局转换器或配置覆盖。

内容的提问来源于stack exchange,提问作者CyberNomad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:25:17