您的问题是想要检索、过滤和传递某些JSON,而无需为该JSON定义完整的数据模型。使用Json.NET,您可以使用
LINQ to JSON 来实现此目的。您的问题是,
是否可以使用 System.Text.Json
来轻松解决这个问题?
截至.NET 6,由于没有
JSONPath支持,使用
System.Text.Json
不能像以前那样轻松地完成这个任务。在此方面通常非常便利。目前有一个未解决的问题
Add JsonPath support to JsonDocument/JsonElement #41537。
话虽如此,假设您有以下JSON:
[
{
"id": 1,
"name": "name 1",
"address": {
"Line1": "line 1",
"Line2": "line 2"
},
}
]
在.NET 6及更高版本中,您可以将JSON解析为
JsonNode
,编辑其内容并返回修改后的JSON。
JsonNode
表示可编辑的JSON文档对象模型,因此最接近于Newtonsoft的
JToken
层次结构。
以下代码显示了一个示例:
而一些
Predicate<long> shouldSkip
过滤方法则指示不应返回具有特定
id
的条目,相当于您问题中的
CHECKS
。您有哪些选项?
var root = JsonNode.Parse(rawJsonDownload).AsArray();
for (int i = root.Count - 1; i >= 0; i--)
{
if (shouldSkip(root[i].AsObject()["id"].GetValue<long>()))
root.RemoveAt(i);
}
return Json(root);
Mockup fiddle #1 在这里
在 .NET Core 3.x 及更高版本中,您可以解析成JsonDocument
并返回一些筛选后的JsonElement
节点。如果过滤逻辑非常简单,并且您不需要以任何其他方式修改JSON,则此方法效果很好。但请注意以下JsonDocument
的限制:
这个问题中的过滤场景足够简单,可以使用以下代码:
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);
这里是第二个模型样例 here。
在任何版本中,您都可以创建一个部分数据模型,仅反序列化需要用于筛选的属性,并将剩余的JSON绑定到[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注入修改变得更加容易。
模拟fiddle #3
在这里。
无论您选择哪种方法,都可以考虑放弃
WebClient
,改用
HttpClient
和使用异步反序列化。例如:
var httpClient = new HttpClient()
var root = await httpClient.GetFromJsonAsync<JsonArray>("WEB API CALL")
或者
using var usersDocument = await JsonDocument.ParseAsync(await httpClient.GetStreamAsync("WEB API CALL"))
或者
var users = await JsonSerializer.DeserializeAsync<List<UserObject>>(await httpClient.GetStreamAsync("WEB API CALL"))
您需要将API方法转换为async
。