你如何使用 System.Text.Json 从一些 json 中读取一个简单的值?

Nic*_*ick 39 c# .net-core system.text.json

我有这个 json

{"id":"48e86841-f62c-42c9-ae20-b54ba8c35d6d"}
Run Code Online (Sandbox Code Playgroud)

我如何48e86841-f62c-42c9-ae20-b54ba8c35d6d摆脱它?我能找到的所有例子都显示做类似的事情

var o = System.Text.Json.JsonSerializer.Deserialize<some-type>(json);
o.id // <- here's the ID!
Run Code Online (Sandbox Code Playgroud)

但是我没有符合这个定义的类型,我不想创建一个。我试过反序列化为动态,但我无法让它工作。

var result = System.Text.Json.JsonSerializer.Deserialize<dynamic>(json);
result.id // <-- An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Linq.Expressions.dll but was not handled in user code: ''System.Text.Json.JsonElement' does not contain a definition for 'id''
Run Code Online (Sandbox Code Playgroud)

任何人都可以提供任何建议吗?


编辑:

我刚刚发现我可以这样做:

Guid id = System.Text.Json.JsonDocument.Parse(json).RootElement.GetProperty("id").GetGuid();
Run Code Online (Sandbox Code Playgroud)

这确实有效 - 但有更好的方法吗?

小智 32

您可以反序列化为Dictionary

var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(json)
Run Code Online (Sandbox Code Playgroud)

或者只是反序列化到Object哪个会产生一个JsonElement你可以调用GetProperty的。

  • `Dictionary&lt;string, object&gt;` 也不是一个糟糕的选择。 (3认同)
  • 使用 System.Text.Json;var json = JsonSerializer.Deserialize&lt;object&gt;(json) as JsonElement?; var tmp = json?.GetProperty("id") (3认同)
  • “或者只是反序列化为 Object,这将生成一个 JsonElement,您可以在其上调用 GetProperty。” 您可以给我举个例子吗? (2认同)
  • 我认为你也可以这样做: var je_root = JsonSerializer.Deserialize&lt;JasonElement&gt;(jsonstr); 然后像这样访问它: int myvalue = je_root.GetProperty("MyProperty").GetProperty("MySubProperty").GetInt32(); (2认同)
  • @Muflix - 如果您需要测试属性是否存在,您可以反序列化为 JsonElement,然后使用 [TryGetProperty](https://docs.microsoft.com/en-us/dotnet/api/system.text.json。 jsonelement.trygetproperty?view=net-5.0#System_Text_Json_JsonElement_TryGetProperty_System_String_System_Text_Json_JsonElement__): `JsonSerializer.Deserialize&lt;JsonElement&gt;().TryGetProperty("SomeProp", out var element)` (2认同)

Ogg*_*las 30

使用JsonObject中添加了对 的支持。.NET 6System.Text.Json.Nodes

例子:

const string Json = "{\"MyNumber\":42, \"MyArray\":[10,11]}";
// dynamic
{
    dynamic obj = JsonNode.Parse(Json);
    int number = (int)obj["MyNumber"];
    Debug.Assert(number == 42);

    obj["MyString"] = "Hello";
    Debug.Assert((string)obj["MyString"] == "Hello");
}

// JsonObject 
{
    JsonObject obj = JsonNode.Parse(Json).AsObject();
    int number = (int)obj["MyNumber"];
    Debug.Assert(number == 42);
    
    obj["MyString"] = "Hello";
    Debug.Assert((string)obj["MyString"] == "Hello");
}
Run Code Online (Sandbox Code Playgroud)

资料来源:

https://github.com/dotnet/runtime/issues/53195

https://github.com/dotnet/runtime/issues/45188


Ale*_*iol 14

我最近将一个项目从 ASP.NET Core 2.2 迁移到 3,我遇到了这种不便。在我们的团队中,我们重视精益依赖,因此我们试图避免包含 Newtonsoft.JSON 并尝试使用System.Text.Json. 我们还决定不将大量 POCO 对象仅用于 JSON 序列化,因为我们的后端模型比 Web API 所需的更复杂。此外,由于非平凡的行为封装,后端模型不能轻松用于序列化/反序列化 JSON 字符串。

我知道这System.Text.Json应该比 Newtonsoft.JSON 更快,但我相信这与从/到特定 POCO 类的 ser/deser 有很大关系。无论如何,速度不在我们这个决定的利弊列表中,所以 YMMV。

长话短说,暂时我写了一个小的动态对象包装器,它JsonElement从 System.Text.Json解包s 并尝试尽可能最好地转换/转换。典型的用法是将请求体作为动态对象读取。同样,我很确定这种方法会扼杀任何速度提升,但这不是我们用例的问题。

这是课程:

    public class ReflectionDynamicObject : DynamicObject {
        public JsonElement RealObject { get; set; }

        public override bool TryGetMember (GetMemberBinder binder, out object result) {
            // Get the property value
            var srcData = RealObject.GetProperty (binder.Name);

            result = null;

            switch (srcData.ValueKind) {
                case JsonValueKind.Null:
                    result = null;
                    break;
                case JsonValueKind.Number:
                    result = srcData.GetDouble ();
                    break;
                case JsonValueKind.False:
                    result = false;
                    break;
                case JsonValueKind.True:
                    result = true;
                    break;
                case JsonValueKind.Undefined:
                    result = null;
                    break;
                case JsonValueKind.String:
                    result = srcData.GetString ();
                    break;
                case JsonValueKind.Object:
                    result = new ReflectionDynamicObject {
                        RealObject = srcData
                    };
                    break;
                case JsonValueKind.Array:
                    result = srcData.EnumerateArray ()
                        .Select (o => new ReflectionDynamicObject { RealObject = o })
                        .ToArray ();
                    break;
            }

            // Always return true; other exceptions may have already been thrown if needed
            return true;
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是一个示例用法,用于解析请求正文 - 一部分位于我所有 WebAPI 控制器的基类中,它将正文公开为动态对象:

    [ApiController]
    public class WebControllerBase : Controller {

        // Other stuff - omitted

        protected async Task<dynamic> JsonBody () {
            var result = await JsonDocument.ParseAsync (Request.Body);
            return new ReflectionDynamicObject {
                RealObject = result.RootElement
            };
        }
    }
Run Code Online (Sandbox Code Playgroud)

并且可以像这样在实际控制器中使用:

//[...]
    [HttpPost ("")]
    public async Task<ActionResult> Post () {
        var body = await JsonBody ();
        var name = (string) body.Name;
        //[...]
    }
//[...]
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以根据需要集成对 GUID 或其他特定数据类型的解析 - 而我们都在等待一些官方/框架认可的解决方案。

  • 根据 [docs](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsondocument?view=netcore),“JsonDocument”超出范围时需要被处置-3.1#remarks),以防止内存泄漏。当您需要在文档生命周期之外使用“RootElement”时,必须[克隆](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.clone? view=netcore-3.1#System_Text_Json_JsonElement_Clone)它。 (2认同)

bob*_*h75 9

解析 System.Text.Json 中字符串的实际方法(.NET Core 3+)

        var jsonStr = "{\"id\":\"48e86841-f62c-42c9-ae20-b54ba8c35d6d\"}";
        using var doc = JsonDocument.Parse(jsonStr);
        var root = doc.RootElement;
        var id = root.GetProperty("id").GetGuid();
Run Code Online (Sandbox Code Playgroud)