您的问题是您想要检索、过滤和传递一些 JSON,而不需要为该 JSON 定义完整的数据模型。通过 Json.NET,您可以使用LINQ 到 JSON https://www.newtonsoft.com/json/help/html/LINQtoJSON.htm以此目的。你的问题是,目前可以轻松解决这个问题吗System.Text.Json
?
从 .NET 6 开始,这不能通过以下方式轻松完成System.Text.Json
因为它不支持JSONPath https://goessner.net/articles/JsonPath/这在此类应用中通常非常方便。目前有一个未解决的问题将 JsonPath 支持添加到 JsonDocument/JsonElement #41537 https://github.com/dotnet/corefx/issues/41537跟踪这个。
话虽如此,假设您有以下 JSON:
[
{
"id": 1,
"name": "name 1",
"address": {
"Line1": "line 1",
"Line2": "line 2"
},
// More properties omitted
}
//, Other array entries omitted
]
还有一些Predicate<long> shouldSkip
指示条目是否具有特定的过滤器方法id
不应返回,对应于CHECKS
在你的问题中。你有什么选择?
在 .NET 6 及更高版本中,您可以将 JSON 解析为JsonNode https://learn.microsoft.com/en-us/dotnet/api/system.text.json.nodes.jsonnode?view=net-6.0,编辑其内容,并返回修改后的 JSON。 A JsonNode
代表一个editable https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter?pivots=dotnet-6-0#create-a-jsonnode-dom-with-object-initializers-and-make-changesJSON 文档对象模型,因此与 Newtonsoft 的最接近JToken https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JToken.htm等级制度。
以下代码显示了这样的示例:
var root = JsonNode.Parse(rawJsonDownload).AsArray(); // AsArray() throws if the root node is not an array.
for (int i = root.Count - 1; i >= 0; i--)
{
if (shouldSkip(root[i].AsObject()["id"].GetValue<long>()))
root.RemoveAt(i);
}
return Json(root);
样机小提琴#1here https://dotnetfiddle.net/HGRDeT
在 .NET Core 3.x 及更高版本中,您可以解析为JsonDocument https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsondocument并返回一些过滤后的集合JsonElement https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement nodes。如果过滤逻辑非常简单并且您不需要以任何其他方式修改 JSON,那么这种方法效果很好。但请注意以下限制JsonDocument
:
-
JsonDocument
and JsonElement
是只读的。它们只能用于examineJSON 值,不修改或创建 JSON 值。
-
JsonDocument
是一次性的,实际上必须需要处理最大限度地减少高使用场景中垃圾收集器 (GC) 的影响,根据docs https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsondocument?view=netcore-3.0#remarks。为了返回一个JsonElement
你必须clone https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.clone?view=netcore-3.0#System_Text_Json_JsonElement_Clone it.
问题中的过滤场景很简单,可以使用以下代码:
using var usersDocument = JsonDocument.Parse(rawJsonDownload);
var users = usersDocument.RootElement.EnumerateArray()
.Where(e => !shouldSkip(e.GetProperty("id").GetInt64()))
.Select(e => e.Clone())
.ToList();
return Json(users);
模型小提琴#2here https://dotnetfiddle.net/rO10rE.
在任何版本中,您都可以创建一个partial仅反序列化过滤所需的属性的数据模型,其余 JSON 绑定到[JsonExtensionDataAttribute] https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonextensiondataattribute财产。这应该允许您实现必要的过滤,而无需对整个数据模型进行硬编码。
为此,请定义以下模型:
public class UserObject
{
[JsonPropertyName("id")]
public long Id { get; set; }
[System.Text.Json.Serialization.JsonExtensionDataAttribute]
public IDictionary<string, object> ExtensionData { get; set; }
}
并进行反序列化和过滤,如下:
var users = JsonSerializer.Deserialize<List<UserObject>>(rawJsonDownload);
users.RemoveAll(u => shouldSkip(u.Id));
return Json(users);
此方法确保可以适当地反序列化与过滤相关的属性,而无需对 JSON 的其余部分做出任何假设。虽然这不像使用 LINQ to JSON 那么容易,但总代码复杂性受过滤检查的复杂性限制,而不是 JSON 的复杂性。事实上,我的观点是,在实践中,这种方法比JsonDocument
方法,因为如果以后需要的话,它可以更容易地注入对 JSON 的修改。
模型小提琴#3here https://dotnetfiddle.net/eDvr7K.
无论你选择哪一个,你可能会考虑放弃WebClient
for HttpClient https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netcore-3.0并使用async
反序列化。例如。:
var httpClient = new HttpClient(); // Cache statically and reuse in production
var root = await httpClient.GetFromJsonAsync<JsonArray>("WEB API CALL");
Or
using var usersDocument = await JsonDocument.ParseAsync(await httpClient.GetStreamAsync("WEB API CALL"));
Or
var users = await JsonSerializer.DeserializeAsync<List<UserObject>>(await httpClient.GetStreamAsync("WEB API CALL"));
你需要convert https://stackoverflow.com/a/41453278/3744182你的API方法是async
以及。