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
的序列化器。
似乎建议在 ConfigureServices
和 using
语句中添加 Newtonsoft 是不够的。然而,答案的简洁让我不清楚需要更改什么(我 认为 它是 Razor 标记)。我没有发现任何文档建议任何类似的 webapi(可能是一个属性?这是我已经在使用的)。
我试过的东西
正如所写,模型和转换器确实适用于 .Net 2.1,但我发现较新版本的 Nest 中的反序列化器可能会停止,因为 Description
装饰有 [Text]
。我尝试将其更改为 [Nested]
但没有成功。
完全删除映射属性并使用 [JsonProperty(PropertyName = "metatag.description", ItemConverter = typeof(MetadataDescriptionConverter))]
。没有区别。
在整个 SiteWideSearchResult
模型上使用 JsonConverter 属性,但这也不会执行转换器。 (它也没有在转换器中遇到任何断点。)
从 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" 可能更合适。
我正在使用 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
的序列化器。
ConfigureServices
和 using
语句中添加 Newtonsoft 是不够的。然而,答案的简洁让我不清楚需要更改什么(我 认为 它是 Razor 标记)。我没有发现任何文档建议任何类似的 webapi(可能是一个属性?这是我已经在使用的)。
我试过的东西
正如所写,模型和转换器确实适用于 .Net 2.1,但我发现较新版本的 Nest 中的反序列化器可能会停止,因为
Description
装饰有[Text]
。我尝试将其更改为[Nested]
但没有成功。完全删除映射属性并使用
[JsonProperty(PropertyName = "metatag.description", ItemConverter = typeof(MetadataDescriptionConverter))]
。没有区别。在整个
SiteWideSearchResult
模型上使用 JsonConverter 属性,但这也不会执行转换器。 (它也没有在转换器中遇到任何断点。)
从 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" 可能更合适。