期望END_OBJECT,但找到了FIELD_NAME



我在HttpClient中使用PostAsJsonAsync来查询Elastic,并且它在第12行失败,'通配符';

我使用https://json2csharp.com/将示例JSON转换为c#对象。

这是Newtonsoft正在生成的json,但是失败了。

{
"query": {
"bool": {
"must": [
{
"range": {
"@timestamp": {
"gte": "now-7d",
"lt": "now"
}
},
"wildcard": {
"request.keyword": {
"value": "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive": true
}
}
}
]
}
}
}

这是我提供的一个示例,用于将json转换为c#对象。

{
"query": {
"bool": {
"must": [
{
"range": {
"@timestamp": {
"gte": "now-7d",
"lt": "now"
}
}
},
{
"wildcard": {
"request.keyword": {
"value": "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive": true
}
}
}
]     
}
}
}

都是有效的JSON,但是Elastic只接受第二个JSON。这似乎是期待花括号周围的属性,但我不知道如何让JSON序列化这种方式。

您遇到了代码生成工具(如https://json2csharp.com/)的限制,即它们不能很好地处理隐含的多态性。在这种情况下,您可能需要手动修复生成的类。

考虑以下包含两种不同类型对象的JSON数组:

[{"A" : "a value"},{"B" : "b value"}]

数组包含具有属性A或属性B的对象,但如果您从此JSON生成类,您将获得具有两个属性的单一合并类型:

public class Root
{
public string A { get; set; }
public string B { get; set; }
}

而你真正想要的是:

public interface IRootBase { }
public class A : IRootBase 
{
public string A { get; set; }
}
public class B : IRootBase 
{
public string B { get; set; }
}

给定这样一个模型,您将能够构造一个List<IRootBase>并将其序列化以获得显示的JSON。(并且,要进行反序列化,请参见使用json.net反序列化没有类型信息的多态json类。)

在您的情况下,问题在于"must"的数组值。如您所见,这个数组包含两种不同类型的对象:

[
{
"range":{
"@timestamp":{
"gte":"now-7d",
"lt":"now"
}
}
},
{
"wildcard":{
"request.keyword":{
"value":"/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive":true
}
}
}
]

但是https://json2csharp.com/将创建以下组合类型:

public class Must
{
public Range range { get; set; }
public Wildcard wildcard { get; set; }
}

如果你要创建一个包含两个属性的Must的单个实例的数组,你会得到无效的JSON被Elastic拒绝。

相反,您需要手动修改自动生成的类型,如下所示:

#region Manually created from Must
public interface IMustConstraint { }
public class RangeConstraint : IMustConstraint
{
public Range range { get; set; }
}
public class WildcardConstraint : IMustConstraint
{
public Wildcard wildcard { get; set; }
}
#endregion Manually created from Must
public class Range
{
[JsonProperty("@timestamp")]
public Timestamp Timestamp { get; set; }
}
public class Timestamp
{
public string gte { get; set; }
public string lt { get; set; }
}
public class Wildcard
{
[JsonProperty("request.keyword")]
public RequestKeyword RequestKeyword { get; set; }
}
public class RequestKeyword
{
public string value { get; set; }
public bool case_insensitive { get; set; }
}
public class BoolQuery // Renamed from Bool for clarity
{
public List<IMustConstraint> must { get; set; } // Modified from List<Must>
}
public class Query
{
public BoolQuery @bool { get; set; }
}
public class Root
{
public Query query { get; set; }
}

现在你可以这样做:

Root root = new ()
{
query = new ()
{
@bool = new ()
{
must = new ()
{
new RangeConstraint() { range = new () { Timestamp = new () { gte = "now-7d", lt = "now" } } },
new WildcardConstraint() { wildcard = new () { RequestKeyword = new () { value = "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status", case_insensitive = true } } },
},
},
},
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented);

并创建所需的JSON。

在这里演示小提琴

最新更新