如何在Elasticsearch NEST中序列化类型为JToken或JObject的属性?

6

我正在将Elasticsearch引入C# API项目中。我想利用现有的API模型作为搜索文档,其中许多允许添加自定义数据点。这些使用Json.NET中的JObject类型实现。例如:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public JObject ExtraProps { get; set; }
}

这使用户能够发送如下JSON请求体,非常方便:
{
   "Id": 123,
   "Name": "Thing",
   "ExtraProps": {
      "Color": "red",
      "Size": "large"
   }
}

然而,如果我在NEST中使用这个文档类型,那些额外的属性会以某种方式失去它们的值,序列化为:
{
   "Id": 123,
   "Name": "Thing",
   "ExtraProps": {
      "Color": [],
      "Size": []
   }
}

在ExtraProps中添加一个[Nest.Object]属性并没有改变行为。据我了解,NEST内部使用Json.NET,所以我不希望它在处理Json.NET类型时出现问题。是否有相对简单的解决方法?
下面是我正在考虑的一些选项:
  1. 使用自定义序列化。我开始尝试这条路,但是感觉变得比应该的要复杂,而且我从来没有让它起作用。

  2. JObject 映射到 Dictionary<string, object>。我已经验证了这个方法的可行性,但如果有嵌套对象(可能会出现),我将需要使用递归来增强它。理想情况下,我希望这可以与更通用的 JToken 类型一起使用。虽然这是我倾向于的选项,但再次感觉比应该的要复杂。

  3. 使用"低级"客户端甚至是原始的HTTP调用。诚然,我还没有探索过这个,但如果它真的比其他方案更简单/更干净,我会考虑采用它。

  4. 报告这个问题。无论如何我都会做这件事。我只是有一种预感,这应该可以直接使用 JObject 或任何 JToken,除非这是预期行为的某些原因。

1个回答

14

这是NEST 6.x的预期行为。

NEST使用Json.NET进行序列化。然而,在NEST 6.x中,该依赖关系已被内部化到NEST程序集中,通过:

  • 将所有Json.NET类型IL合并到NEST程序集中
  • 将Newtonsoft.Json内的类型重命名为Nest.Json
  • 将所有类型标记为internal

有一篇博客文章详细说明了这种改变背后的动机。

当处理Json.NET类型(如Newtonsoft.Json.Linq.JObject)时,Json.NET会对这些类型进行特殊处理以进行序列化/反序列化。但是,在内部化的Json.NET中,NEST 6.x不知道如何特别处理Newtonsoft.Json.Linq.JObject,因为内部化的Json.NET中的所有类型都被重命名为Nest.Json命名空间。

为了支持Json.NET类型,需要连接使用Json.NET来序列化文档的序列化器。创建了NEST.JsonNetSerializer nuget包来帮助解决此问题。只需将对NEST.JsonNetSerializer的引用添加到项目中,然后按以下方式连接序列化器即可。

// choose the appropriate IConnectionPool for your use case
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings =
    new ConnectionSettings(pool, JsonNetSerializer.Default);
var client = new ElasticClient(connectionSettings);

有了这个设置,带有 JObject 属性的文档将按预期进行序列化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接