Search code examples
jsonvb.netjson.netdeserializationshopify

How to ignore missing nodes when deserialising json in .NET


Some of the Shopify API's don't return nodes when they are not configured rather than returning null values.

JSON EXAMPLE

{
  "orders": [
    {
      "id": 1,
      "customer": {
        "id": 001,
      }
    },
    {
      "id": 2
    }
  ]
}

In order to deserialise the Json I need to include all properties within the class object.

Public Class AllOrders
  Public Property orders() As List(Of Order)
End Class

Public Class Order
  Public Property id As Long?
  Public Property customer() As Customer
End Class

Public Class Customer
  Public Property id As Long?
End Class

How I can efficiently skip missing nodes without convoluted if statements.

The issue is not the deserialisation of the json but trying to read a named member that does not exist.

Dim AllOrders = JsonConvert.DeserializeObject(Of AllOrders)(GetOrders())

For Each order As Shopify.Order In AllOrders.orders
  Dim test as order.customer.id
  'Error NullReferenceException on customer
Next

Can this be handled within the Json.Net framework?


JsonSerializerSettings

I should note I have already tried the following settings.

Dim settings = New JsonSerializerSettings With {
  .NullValueHandling = NullValueHandling.Ignore,
  .MissingMemberHandling = MissingMemberHandling.Ignore
}

Solution

  • There are a couple of client-side alternatives for handling this in one line.

    You could use the null conditional operator ?., as in

    Dim oneId = order.Customer?.Id
    

    In this case, the result is a nullable Long, but Id is already a nullable long, so it shouldn't change subsequent handling as you already needed to account for the possibility that it might be null. If there is a single "sensible" value for a missing value, you can then use GetValueOrDefault to have a guaranteed value.

    You could use the null coalescing form of the If operator, as in

    Dim guaranteedCustomer = If(order.Customer, defaultCustomer)
    

    This would require some caution as using a single mutable object as your default is potentially a recipe for nasty bugs later when one of the defaults gets mutated thus changing all of the defaulted items.