NewtonSoft JsonConverter 未在 ASP.NET Core 3.1 和 Elasticsearch 中触发

NewtonSoft JsonConverter not firing in ASP.NET Core 3.1 with Elasticsearch

我正在使用 Web API 从 Elasticsearch 数据库检索数据。数据库由我无法修改的完全不同的软件组成。数据中的一个字段 metatag.description 应该用单个值填充,但有时由于上游数据中的错误而以一组值结尾。 (我也无法修改它们,它是 ~200 个网站的集合。)

之前通过向模型的相关成员添加自定义 JsonConverter 来处理不一致的数据结构。

将项目从 ASP.NET Core 2.1 更新到 3.1 后,从 Elasticsearch 反序列化对象时不再调用自定义 JsonConverter

项目文件引用了 Microsoft.AspNetCore.Mvc.NewtonsoftJson 包。

<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.*" />

Newtonsoft.Json 在 ConfigureServices():

中初始化
services.AddControllers().AddNewtonsoftJson();

模型的简化版本如下所示(完整文件包括 using Newtonsoft.Json;)。该模型只有一个 Description 字段,但有时上游数据源会发送一个数组而不是单个值。 (我们无法合理修复上游源码。)

public class SiteWideSearchResult
{
    [Text(Name = "title")]
    public string Title { get; set; }

    [Text(Name = "metatag.description")]
    [JsonConverter(typeof(MetadataDescriptionConverter))]
    public string Description { get; set; }
}

JsonConverter目前看起来是这样的,但是执行了这些行中的none,设置时也没有到达任何断点(这个完整的文件还包括using Newtonsoft.Json;):

public class MetadataDescriptionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

如上所述,有两个版本的结构被反序列化。 JsonConverter 旨在处理这两者并允许将(可能更改的)数据版本存储在模型中。

因为它匹配模型,这个版本反序列化正确:

      {
        "_index": "myindex",
        "_type": "doc",
        "_id": "item_id_1",
        "_score": 4.3536105,
        "_source": {
          "metatag.description": "Single description entry",
          "title": "This structure works"
        }
      }

此版本旨在由自定义 JsonConverter 处理。事实上,它失败了。

      {
        "_index": "myindex",
        "_type": "doc",
        "_id": "item_id_2",
        "_score": 4.3536105,
        "_source": {
          "metatag.description": [
             "First description line",
             "Second description line"
          ],
          "title": "This structure fails"
        }
      }

第二个结构的错误是 expected:'String Begin Token', actual:'[',这是有道理的,但这正是转换器要解决的问题。除了,它没有被调用。

我怀疑正在使用 System.Text.Json 序列化器而不是来自 Newtonsoft.Json 的序列化器。

似乎建议在 ConfigureServicesusing 语句中添加 Newtonsoft 是不够的。然而,答案的简洁让我不清楚需要更改什么(我 认为 它是 Razor 标记)。我没有发现任何文档建议任何类似的 webapi(可能是一个属性?这是我已经在使用的)。

我试过的东西

Newtonsoft.JSON 到本机 System.Text.Json.Serialization 的 ASP.NET 核心更改是转移注意力。

真正的罪魁祸首是 Elasticsearch NEST 客户端版本 7.x 的更改。 As of version 7.0, NEST no longer uses Newtonsoft.Json internally.

对于从 Elasticsearch 检索数据时反序列化的特定情况,正确的方法似乎是指定自定义序列化程序,如该页面所述。

对于我的特定用例,解决方案是通过在 ConnectionSettings 构造函数的调用中添加 sourceSerializer: JsonNetSerializer.Default 来使用 JsonNetSerializer .

var connectionSettings =
    new ConnectionSettings(pool, sourceSerializer: JsonNetSerializer.Default);
var client = new ElasticClient(connectionSettings);

另一方面,如果自定义映射的需要扩展到索引创建时间,自定义 "Visitor Pattern mapping" 可能更合适。