0

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

3
  • 1
    Is there a reason why you havent made POCO classes that represent this data so you can quickly and easily serialize/deserialize into that structure? Commented May 12, 2020 at 21:24
  • Damian, try pasting that json into this site. I just tried it and I looks like it all checks out. Having an C# object you can deserialize should make data manipulation a little easier. jsonutils.com Commented May 13, 2020 at 2:02
  • Thanks Guys, the issue i have is that the Json i get back changes depending on the environment i query, and thus some nodes are not presented, When i try to map these to a POCO I quite often have this fail. So my approach was to try keep the object generic, and reference just the nodes that mattered to me, as they appear to be present always - just maybe empty arrays Commented May 13, 2020 at 21:35

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

1 Comment

thank you for your fast respone. I was trying to not create a PoCo for this scenario; as the data set is unpredictable, but based on a fixed structure this is a perfect fix for my terrible code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.