使用随机根元素反序列化 JSON 数组时出现问题

Trouble deserializing JSON array with random root element

我有这个json:

{
  "f6a1ad82-4b5f-430d-92a0-817927f5beaa": [
    {
      "id": "5a9d3ae5fcf53960035643a7",
      "state": "RUNNING",
      "started_at": "2021-09-20T10:15:49.613Z",
      "detailed_message": null,
      "message_input": {
        "title": "Windows Event Logs",
        "global": true,
        "name": "GELF TCP",
        "content_pack": null,
        "created_at": "2018-03-05T12:48:16.447Z",
        "type": "org.graylog2.inputs.gelf.tcp.GELFTCPInput",
        "creator_user_id": "adminuser",
        "attributes": {
          "recv_buffer_size": 1048576,
          "tcp_keepalive": false,
          "use_null_delimiter": true,
          "tls_client_auth_cert_file": "",
          "bind_address": "0.0.0.0",
          "tls_cert_file": "",
          "decompress_size_limit": 8388608,
          "port": 12200,
          "tls_key_file": "",
          "tls_enable": false,
          "tls_key_password": "",
          "max_message_size": 2097152,
          "tls_client_auth": "disabled",
          "override_source": null
        },
        "static_fields": {},
        "node": null,
        "id": "5a9d3ae5fcf123453a7"
      }
    },
    {
      "id": "5a94423bfcf53920285e3a3b",
      "state": "RUNNING",
      "started_at": "2021-09-20T10:15:49.609Z",
      "detailed_message": null,
      "message_input": {
        "title": "Apache Filebeat",
        "global": true,
        "name": "Beats (deprecated)",
        "content_pack": null,
        "created_at": "2018-02-26T17:50:30.581Z",
        "type": "org.graylog.plugins.beats.BeatsInput",
        "creator_user_id": "adminuser",
        "attributes": {
          "recv_buffer_size": 1048576,
          "port": 5040,
          "tls_key_file": "",
          "tls_enable": false,
          "tls_key_password": "",
          "tcp_keepalive": false,
          "tls_client_auth_cert_file": "",
          "tls_client_auth": "disabled",
          "override_source": null,
          "bind_address": "0.0.0.0",
          "tls_cert_file": ""
        },
        "static_fields": {},
        "node": null,
        "id": "5a94423bfcf53555555e3a3b"
      }
    }
  ]
}

使用 QuickType 我有这个 class 我正在尝试反序列化为:

namespace Phono.Packages.GraylogLowLevelRESTClient.Models
{
    using System;
    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    [JsonObject]
    public partial class ClusterInputstates
    {
        [JsonProperty("f6a1ad82-4b5f-430d-92a0-817927f5beaa")]
        public NodeId[] NodeId { get; set; }
    }

    public partial class NodeId
    {
        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("state")]
        public string State { get; set; }

        [JsonProperty("started_at")]
        public DateTimeOffset StartedAt { get; set; }

        [JsonProperty("detailed_message")]
        public string DetailedMessage { get; set; }

        [JsonProperty("message_input")]
        public MessageInput MessageInput { get; set; }
    }

    public partial class MessageInput
    {
        [JsonProperty("title")]
        public string Title { get; set; }

        [JsonProperty("global")]
        public bool Global { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("content_pack")]
        public object ContentPack { get; set; }

        [JsonProperty("created_at")]
        public DateTimeOffset CreatedAt { get; set; }

        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("creator_user_id")]
        public string CreatorUserId { get; set; }

        [JsonProperty("attributes")]
        public Attributes Attributes { get; set; }

        [JsonProperty("static_fields")]
        public StaticFields StaticFields { get; set; }

        [JsonProperty("node")]
        public Guid? Node { get; set; }

        [JsonProperty("id")]
        public string Id { get; set; }
    }

    public partial class Attributes
    {
        [JsonProperty("recv_buffer_size", NullValueHandling = NullValueHandling.Ignore)]
        public long? RecvBufferSize { get; set; }

        [JsonProperty("tcp_keepalive", NullValueHandling = NullValueHandling.Ignore)]
        public bool? TcpKeepalive { get; set; }

        [JsonProperty("use_null_delimiter", NullValueHandling = NullValueHandling.Ignore)]
        public bool? UseNullDelimiter { get; set; }

        [JsonProperty("tls_client_auth_cert_file", NullValueHandling = NullValueHandling.Ignore)]
        public string TlsClientAuthCertFile { get; set; }

        [JsonProperty("bind_address", NullValueHandling = NullValueHandling.Ignore)]
        public string BindAddress { get; set; }

        [JsonProperty("tls_cert_file", NullValueHandling = NullValueHandling.Ignore)]
        public string TlsCertFile { get; set; }

        [JsonProperty("decompress_size_limit", NullValueHandling = NullValueHandling.Ignore)]
        public long? DecompressSizeLimit { get; set; }

        [JsonProperty("port", NullValueHandling = NullValueHandling.Ignore)]
        public long? Port { get; set; }

        [JsonProperty("tls_key_file", NullValueHandling = NullValueHandling.Ignore)]
        public string TlsKeyFile { get; set; }

        [JsonProperty("tls_enable", NullValueHandling = NullValueHandling.Ignore)]
        public bool? TlsEnable { get; set; }

        [JsonProperty("tls_key_password", NullValueHandling = NullValueHandling.Ignore)]
        public string TlsKeyPassword { get; set; }

        [JsonProperty("max_message_size", NullValueHandling = NullValueHandling.Ignore)]
        public long? MaxMessageSize { get; set; }

        [JsonProperty("tls_client_auth", NullValueHandling = NullValueHandling.Ignore)]
        public string TlsClientAuth { get; set; }

        [JsonProperty("override_source")]
        public object OverrideSource { get; set; }

        [JsonProperty("heartbeat", NullValueHandling = NullValueHandling.Ignore)]
        public long? Heartbeat { get; set; }

        [JsonProperty("prefetch", NullValueHandling = NullValueHandling.Ignore)]
        public long? Prefetch { get; set; }

        [JsonProperty("exchange_bind", NullValueHandling = NullValueHandling.Ignore)]
        public bool? ExchangeBind { get; set; }

        [JsonProperty("broker_vhost", NullValueHandling = NullValueHandling.Ignore)]
        public string BrokerVhost { get; set; }

        [JsonProperty("broker_username", NullValueHandling = NullValueHandling.Ignore)]
        public string BrokerUsername { get; set; }

        [JsonProperty("broker_port", NullValueHandling = NullValueHandling.Ignore)]
        public long? BrokerPort { get; set; }

        [JsonProperty("parallel_queues", NullValueHandling = NullValueHandling.Ignore)]
        public long? ParallelQueues { get; set; }

        [JsonProperty("broker_password", NullValueHandling = NullValueHandling.Ignore)]
        public string BrokerPassword { get; set; }

        [JsonProperty("throttling_allowed", NullValueHandling = NullValueHandling.Ignore)]
        public bool? ThrottlingAllowed { get; set; }

        [JsonProperty("exchange", NullValueHandling = NullValueHandling.Ignore)]
        public string Exchange { get; set; }

        [JsonProperty("tls", NullValueHandling = NullValueHandling.Ignore)]
        public bool? Tls { get; set; }

        [JsonProperty("routing_key", NullValueHandling = NullValueHandling.Ignore)]
        public string RoutingKey { get; set; }

        [JsonProperty("requeue_invalid_messages", NullValueHandling = NullValueHandling.Ignore)]
        public bool? RequeueInvalidMessages { get; set; }

        [JsonProperty("broker_hostname", NullValueHandling = NullValueHandling.Ignore)]
        public string BrokerHostname { get; set; }

        [JsonProperty("queue", NullValueHandling = NullValueHandling.Ignore)]
        public string Queue { get; set; }

        [JsonProperty("idle_writer_timeout", NullValueHandling = NullValueHandling.Ignore)]
        public long? IdleWriterTimeout { get; set; }

        [JsonProperty("max_chunk_size", NullValueHandling = NullValueHandling.Ignore)]
        public long? MaxChunkSize { get; set; }

        [JsonProperty("enable_cors", NullValueHandling = NullValueHandling.Ignore)]
        public bool? EnableCors { get; set; }

        [JsonProperty("force_rdns", NullValueHandling = NullValueHandling.Ignore)]
        public bool? ForceRdns { get; set; }

        [JsonProperty("store_full_message", NullValueHandling = NullValueHandling.Ignore)]
        public bool? StoreFullMessage { get; set; }

        [JsonProperty("expand_structured_data", NullValueHandling = NullValueHandling.Ignore)]
        public bool? ExpandStructuredData { get; set; }

        [JsonProperty("allow_override_date", NullValueHandling = NullValueHandling.Ignore)]
        public bool? AllowOverrideDate { get; set; }
    }

    public partial class StaticFields
    {
    }

    public partial class ClusterInputstates
    {
        public static ClusterInputstates FromJson(string json) => JsonConvert.DeserializeObject<ClusterInputstates>(json, Phono.Packages.GraylogLowLevelRESTClient.Models.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this ClusterInputstates self) => JsonConvert.SerializeObject(self, Phono.Packages.GraylogLowLevelRESTClient.Models.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

它有效,但我无法反序列化,除非我在 JsonPropery 中明确指定第一个元素。

即:[JsonProperty("f6a1ad82-4b5f-430d-92a0-817927f5beaa")]

实际上,这个 属性 是一个 GUID,并且随时都可能发生变化(以及多个 GUID 对象在它们自己的数组中的可能性)。

我试过以下变体:

public Dictionary<string, NodeId[]> NodeId { get; set; }

但这要么导致 exception/failure 反序列化,要么返回的对象为空。

我错过了什么?

这是使用 Visual Studio 2019 和序列化库进行测试的。一切正常。

使用Newtonsoft.Json

 var deserializedJson= JsonConvert.DeserializeObject<Dictionary<string, List<Message>>>(json);

如何使用(示例)

List<Message> result =  deserializedJson.Values.FirstOrDefault();

var startedAt=result[0].StartedAt;
//or
 var startedAt=result.FirstOrDefault().StartedAt;

var  port0=result[0].MessageInput.Attributes.Port;
//or
var  port0=result.Where(r => r.Id== "5a9d3ae5fcf53960035643a7").FirstOrDefault()
.MessageInput.Attributes.Port;

var port1 = result[1].MessageInput.Attributes.Port;

输出

2021-09-20 10:15:49 AM +00:00
12200
5040

public partial class Message
    {
        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("state")]
        public string State { get; set; }

        [JsonProperty("started_at")]
        public DateTimeOffset StartedAt { get; set; }

        [JsonProperty("detailed_message")]
        public object DetailedMessage { get; set; }

        [JsonProperty("message_input")]
        public MessageInput MessageInput { get; set; }
    }

    public partial class MessageInput
    {
        [JsonProperty("title")]
        public string Title { get; set; }

        [JsonProperty("global")]
        public bool Global { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("content_pack")]
        public object ContentPack { get; set; }

        [JsonProperty("created_at")]
        public DateTimeOffset CreatedAt { get; set; }

        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("creator_user_id")]
        public string CreatorUserId { get; set; }

        [JsonProperty("attributes")]
        public Attributes Attributes { get; set; }

        [JsonProperty("static_fields")]
        public StaticFields StaticFields { get; set; }

        [JsonProperty("node")]
        public object Node { get; set; }

        [JsonProperty("id")]
        public string Id { get; set; }
    }

    public partial class Attributes
    {
        [JsonProperty("recv_buffer_size")]
        public long RecvBufferSize { get; set; }

        [JsonProperty("tcp_keepalive")]
        public bool TcpKeepalive { get; set; }

        [JsonProperty("use_null_delimiter", NullValueHandling = NullValueHandling.Ignore)]
        public bool? UseNullDelimiter { get; set; }

        [JsonProperty("tls_client_auth_cert_file")]
        public string TlsClientAuthCertFile { get; set; }

        [JsonProperty("bind_address")]
        public string BindAddress { get; set; }

        [JsonProperty("tls_cert_file")]
        public string TlsCertFile { get; set; }

        [JsonProperty("decompress_size_limit", NullValueHandling = NullValueHandling.Ignore)]
        public long? DecompressSizeLimit { get; set; }

        [JsonProperty("port")]
        public long Port { get; set; }

        [JsonProperty("tls_key_file")]
        public string TlsKeyFile { get; set; }

        [JsonProperty("tls_enable")]
        public bool TlsEnable { get; set; }

        [JsonProperty("tls_key_password")]
        public string TlsKeyPassword { get; set; }

        [JsonProperty("max_message_size", NullValueHandling = NullValueHandling.Ignore)]
        public long? MaxMessageSize { get; set; }

        [JsonProperty("tls_client_auth")]
        public string TlsClientAuth { get; set; }

        [JsonProperty("override_source")]
        public object OverrideSource { get; set; }
    }

    public partial class StaticFields
    {
    }