简体   繁体   中英

C# LINQ Query to List of Nested JSON

I have been attempting to create a LINQ query in C# which will allow me to create a List<> from different properties in the JSON string, which are of interest to me.

I have attempted a number of different approaches of.Select() and.SelectMany() but always end up with creating an exception. To unblock I have resorted to creating 2 or 3 independent Linq Queries which will extract the data I care about and then append these to a List.

Of course, this is utterly ugly; and therefore I am here asking from some guidance on how to do this correctly. I am not a professional developer, and IT Pro lost in DevOps; so please be kind!

This is a sample of the JSON payload

{
  "value": [
    {
      "name": "p-we1net-network-vnet",
      "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet",
      "type": "Microsoft.Network/virtualNetworks",
      "location": "westeurope",
      "tags": {
        "IaCVersion": "logsRetentionDays-20200505.02",
        "ConfigVersion": "1.0.0.0"
      },
      "properties": {
        "provisioningState": "Succeeded",
        "resourceGuid": "e7619105-bd1c-4110-b19f-f465c5743899",
        "addressSpace": {
          "addressPrefixes": [
            "99.111.0.0/22"
          ]
        },
        "dhcpOptions": {
          "dnsServers": []
        },
        "subnets": [
          {
            "name": "GatewaySubnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/subnets/GatewaySubnet",
            "properties": {
              "provisioningState": "Succeeded",
              "addressPrefix": "99.111.0.0/24",
              "routeTable": {
                "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/routeTables/p-we1net-network-vnet-GatewaySubnet-rt"
              },
              "ipConfigurations": [
                {
                  "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworkGateways/p-we1net-network-vpn/ipConfigurations/vnetGatewayConfig"
                }
              ],
              "serviceEndpoints": [
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.Storage",
                  "locations": [
                    "westeurope",
                    "northeurope"
                  ]
                }
              ],
              "delegations": [],
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            },
            "type": "Microsoft.Network/virtualNetworks/subnets"
          },
          {
            "name": "AzureFirewallSubnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/subnets/AzureFirewallSubnet",
            "properties": {
              "provisioningState": "Succeeded",
              "addressPrefix": "99.111.1.0/24",
              "routeTable": {
                "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/routeTables/p-we1net-network-vnet-AzureFirewallSubnet-rt"
              },
              "ipConfigurations": [
                {
                  "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/azureFirewalls/p-we1net-network-fw/azureFirewallIpConfigurations/p-we1net-network-fw-pip001"
                }
              ],
              "serviceEndpoints": [
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.AzureActiveDirectory",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.AzureCosmosDB",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.CognitiveServices",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.ContainerRegistry",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.EventHub",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.KeyVault",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.ServiceBus",
                  "locations": [
                    "*"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.Sql",
                  "locations": [
                    "westeurope"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.Storage",
                  "locations": [
                    "westeurope",
                    "northeurope"
                  ]
                },
                {
                  "provisioningState": "Succeeded",
                  "service": "Microsoft.Web",
                  "locations": [
                    "*"
                  ]
                }
              ],
              "delegations": [],
              "privateEndpointNetworkPolicies": "Enabled",
              "privateLinkServiceNetworkPolicies": "Enabled"
            },
            "type": "Microsoft.Network/virtualNetworks/subnets"
          }
        ],
        "virtualNetworkPeerings": [
          {
            "name": "p-we1waf-network-vnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/virtualNetworkPeerings/p-we1waf-network-vnet",
            "properties": {
              "provisioningState": "Succeeded",
              "resourceGuid": "dee9953a-82b7-0f66-01ad-c11f82585928",
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "/subscriptions/guid/resourceGroups/p-we1waf-network/providers/Microsoft.Network/virtualNetworks/p-we1waf-network-vnet"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": false,
              "allowGatewayTransit": true,
              "useRemoteGateways": false,
              "doNotVerifyRemoteGateways": false,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "99.111.4.0/22"
                ]
              },
              "routeServiceVips": {}
            },
            "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
          },
          {
            "name": "p-we1dc-network-vnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/virtualNetworkPeerings/p-we1dc-network-vnet",
            "properties": {
              "provisioningState": "Succeeded",
              "resourceGuid": "e3fad777-dac9-037a-1814-3609d6a3286c",
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "/subscriptions/guid/resourceGroups/p-we1dc-network/providers/Microsoft.Network/virtualNetworks/p-we1dc-network-vnet"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": false,
              "allowGatewayTransit": true,
              "useRemoteGateways": false,
              "doNotVerifyRemoteGateways": false,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "99.111.8.0/25"
                ]
              },
              "routeServiceVips": {}
            },
            "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
          },
          {
            "name": "p-we1rmt-network-vnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/virtualNetworkPeerings/p-we1rmt-network-vnet",
            "properties": {
              "provisioningState": "Succeeded",
              "resourceGuid": "2e9593b3-d730-0251-1e39-87d3b767cc06",
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "/subscriptions/guid/resourceGroups/p-we1rmt-network/providers/Microsoft.Network/virtualNetworks/p-we1rmt-network-vnet"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": false,
              "allowGatewayTransit": true,
              "useRemoteGateways": false,
              "doNotVerifyRemoteGateways": false,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "99.111.8.128/25"
                ]
              },
              "routeServiceVips": {}
            },
            "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
          },
          {
            "name": "t-tstsp1-network-vnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/virtualNetworkPeerings/t-tstsp1-network-vnet",
            "properties": {
              "provisioningState": "Succeeded",
              "resourceGuid": "4ed7d2c0-ecba-06ae-0cc5-90595382193c",
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "/subscriptions/guid/resourceGroups/t-tstsp1-network/providers/Microsoft.Network/virtualNetworks/t-tstsp1-network-vnet"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": false,
              "allowGatewayTransit": true,
              "useRemoteGateways": false,
              "doNotVerifyRemoteGateways": false,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "99.111.9.0/25"
                ]
              },
              "routeServiceVips": {}
            },
            "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
          },
          {
            "name": "t-tstsp2-network-vnet",
            "id": "/subscriptions/guid/resourceGroups/p-we1net-network/providers/Microsoft.Network/virtualNetworks/p-we1net-network-vnet/virtualNetworkPeerings/t-tstsp2-network-vnet",
            "properties": {
              "provisioningState": "Succeeded",
              "resourceGuid": "8a4eb533-d883-0725-13a8-ebd4d3973fbe",
              "peeringState": "Connected",
              "remoteVirtualNetwork": {
                "id": "/subscriptions/guid/resourceGroups/t-tstsp2-network/providers/Microsoft.Network/virtualNetworks/t-tstsp2-network-vnet"
              },
              "allowVirtualNetworkAccess": true,
              "allowForwardedTraffic": false,
              "allowGatewayTransit": true,
              "useRemoteGateways": false,
              "doNotVerifyRemoteGateways": false,
              "remoteAddressSpace": {
                "addressPrefixes": [
                  "99.111.9.128/25"
                ]
              },
              "routeServiceVips": {}
            },
            "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
          }
        ],
        "enableDdosProtection": false,
        "enableVmProtection": false
      }
    }
  ]
}

What I am looking to extract to a list is the following nodes, to an object/class

NetworkName (string)
["Value"][0][Name]

HostNetwork (List) ["Value"][0][properties][addressPrefixes]

PeeredNets (List) ["Value"][0][properties][virtualNetworkPeerings][x][properties][remoteAddressSpace][addressPrefixes]

Now, for the embarrassing part, this is the code I created; feel free to redact this: :)

try {
          JObject root = JObject.Parse(response);

          // Get the VNET Name
          cidrData.name = root["value"][0]["name"].ToString();
          Console.WriteLine($"Name: {cidrData}");

          // Get the Supernets
          JArray superNet = new JArray(root["value"][0]["properties"]["addressSpace"]["addressPrefixes"]);
          cidrData.supernet = superNet.FirstOrDefault()[0].ToString();

          foreach(var item in superNet){
            Console.WriteLine($"SuperNets: {item[0].ToString()}");
          }

          // Get the Subnets
          cidrData.subnets = new List<string>();

          var networkPeeringList = JObject.Parse(response)
            .Descendants()
            .Where(x => x is JObject)
            .Where(x => x["name"] != null )
            .Select(x => new {
              name = (string)x["name"],
              data = (string)x["properties"].ToString()
              })
            .ToList();

          foreach (var peeredNetwork in networkPeeringList)
          {
            Console.WriteLine($" {peeredNetwork.name}");

            var netData = JObject.Parse(peeredNetwork.data)
              .Descendants()
              .Where(x => x is JObject)
              .Where(x => x["addressPrefixes"] != null )
              .Select(x => new {
                name = x["addressPrefixes"]
              })
              .ToList();

            foreach (var record in netData) {
              var subnet = record.name[0].ToString();
              cidrData.subnets.Add(subnet);
              Console.WriteLine($" {subnet}");
            }

          }

        }

Can anyone tell me how to do this more elegantly; preferably with a single LINQ query to cheery pick the values from the JSON?

Cheers

Here's the simple solution you can try. First, map the JSON to Model(POCO) and deserialize the JSON apply LINQ and get an object with all your values.

Model classes for properties you want from JSON.

public partial class Values
{
[JsonProperty("value")] public List<Value> Value { get; set; }
}

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

[JsonProperty("properties")] public ValueProperties Properties { get; set; }
}

public partial class ValueProperties
{
[JsonProperty("addressSpace")] public AddressSpace AddressSpace { get; set; }

[JsonProperty("virtualNetworkPeerings")]
public List<VirtualNetworkPeering> VirtualNetworkPeerings { get; set; }
}

public partial class AddressSpace
{
[JsonProperty("addressPrefixes")] public List<string> AddressPrefixes { get; set; }
}


public partial class VirtualNetworkPeering
{
[JsonProperty("properties")] public VirtualNetworkPeeringProperties Properties { get; set; }
}

public partial class VirtualNetworkPeeringProperties
{
[JsonProperty("remoteAddressSpace")] public AddressSpace RemoteAddressSpace { get; set; }
}

Deserialize the JSON and get desired properites:

var values = JsonConvert.DeserializeObject<Values>(json);
var desiredValues = values.Value
        .Select(x => new
        {
          NetworkName = x.Name,
          HostNetwork = x.Properties.AddressSpace.AddressPrefixes.Select(address => address).ToList(),
          PeeredNets = x.Properties.VirtualNetworkPeerings
            .SelectMany(peering => peering.Properties.RemoteAddressSpace.AddressPrefixes).Select(address => address).ToList()
        }).ToList();

Note This requires you to install Newtonsoft.Json

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM