One of the most common support questions I get regarding the Contentful .NET SDK is. Why are some of my items null? Sometimes it's assets, sometimes it's entries and it's really hard to understand why. Today I finally decided to try to shed some light on this particular issue.

TLDR: Set ResolveEntriesSelectively to true on your IContentfulClient and it will skip any properties that your models doesn't include by using reflection to inspect the models before deserializing.

The problem illuminated

When fetching items from Contentful it is returned in a json format that looks like this:

{
  "sys": {
    "type": "Array"
  },
  "total": 2,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "sys": {
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "SpaceId"
          }
        },
        "id": "Bob",
        "type": "Entry",
        "createdAt": "2016-11-15T07:35:13.166Z",
        "updatedAt": "2016-11-15T08:42:59.137Z",
        "revision": 3,
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "Person"
          }
        },
        "locale": "en-US"
      },
      "fields": {
        "name": "Bob",
        "profession":
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "Developer"
            }
          }
      }
    }
    {
      "sys": {
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "SpaceId"
          }
        },
        "id": "Alice",
        "type": "Entry",
        "createdAt": "2016-11-15T07:35:13.166Z",
        "updatedAt": "2016-11-15T08:42:59.137Z",
        "revision": 3,
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "Person"
          }
        },
        "locale": "en-US"
      },
      "fields": {
        "name": "Alice",
        "profession":
          {
            "sys": {
              "type": "Link",
              "linkType": "Entry",
              "id": "Developer"
            }
          }
      }
    }
  ],
  "includes": {
    "Entry": [
      {
      "sys": {
        "space": {
          "sys": {
            "type": "Link",
            "linkType": "Space",
            "id": "SpaceId"
          }
        },
        "id": "Developer",
        "type": "Entry",
        "createdAt": "2016-11-15T07:35:13.166Z",
        "updatedAt": "2016-11-15T08:42:59.137Z",
        "revision": 3,
        "contentType": {
          "sys": {
            "type": "Link",
            "linkType": "ContentType",
            "id": "Profession"
          }
        },
        "locale": "en-US"
      },
      "fields": {
        "name": "Developer"
      }
    ],
    "Asset": [
    ]
  }
}

The important parts here are the "items" array and the "includes" part of the response. The "items" will contain the actual entries you requested from Contentful, the "includes" will contain two arrays "Entry" and "Asset" which will contain the entries and assets that your requested items reference. In the example above the response contains two entries of type Person that both reference an entry of type Profession, this profession entry is present in the Entry part of the includes array.

This way of structuring the response is to avoid circular referencing. The actual reference in the response just points to an entry in the includes array by its id. That means that no matter how complex the structure of your content model is, it will always be able to be represented without breaking down in an endless loop of references back and forth.

In the .NET SDK the response from Contentful is represented as a ContentfulCollection<T>, a collection type that contains properties for Total, Skip, Limit as in the response above as well as collection properties for Items, IncludedAssets and IncludedEntries.

In .NET you would normally use a class to represent the content you want to fetch from Contentful. For example the response above would be fetched in the .NET SDK something like this.

First a model to represent the persons we are fetching from Contentful.

public class Person {
  public string Name { get; set; }
  public Profession Profession { get; set; }
}

Note how we represent the referenced profession with a strongly typed class as well.

public class Profession {
  public string Name { get; set; }
}

Then we query Contentful for our entries something like this.


var entries = await contentfulClient.GetEntries(QueryBuilder<Person>.New.ContentTypeIs("Person"));
Console.WriteLine(entries.First().Name); // Bob
Console.WriteLine(entries.Last().Name); // Alice
Console.WriteLine(entries.First().Profession.Name); // Developer

Here it's important to notice that we do not need to use the IncludedEntries property of the collection at all. The .NET SDK has already resolved the reference for us.

The way this is done is by traversing the JSON structure before deserialization and actually copying parts of the response from the Entry and Asset part of the response into the items array. If an item is referenced more than once it will be replaced by a reference token $ref that points to the $id of the entry that was first found. Here's how the response above would look after this transformation (the sys properties has been omitted for brevity).

{
  "sys": {
    "type": "Array"
  },
  "total": 2,
  "skip": 0,
  "limit": 100,
  "items": [
    {
      "sys": {
        // omitted
      },
      "fields": {
        "name": "Bob",
        "profession":
          {
            "$id": "Developer",
            "sys": {
              "id": "Developer"
              // omitted
            },
            "fields": {
              "name": "Developer"
            }
          }
      }
    }
    {
      "sys": {
       // omitted
      },
      "fields": {
        "name": "Alice",
        "profession":
          {
            "$ref": "Developer",
          }
      }
    }
  ],
  "includes": {
    "Entry": [
      {
        "sys": {
          "id": "Developer"
          // omitted
        },
        "fields": {
          "name": "Developer"
        }
      }
    ],
    "Asset": [
    ]
  }
}

Notice how the developer entry has been copied up to Bobs profession field and how an $id property has been added. Alice developer entry has been replaced with a $ref property that points to the $id property above. This is all part of the way that Json.NET handles references in JSON structures.

This works fine, so what is the problem?

Well, the problem arises when we have models that do not contain the entire JSON structure and thus might not include the $id object.

Imagine we had the following entry structure.


"fields": {
        "name": "Bob",
        "profession":
          {
            "sys": {
              "id": "Developer"
              // omitted
            },
            "fields": {
              "name": "Bob",
              "profession":
                {
                  "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "Developer"
                  }
                },
              "friends": [
                {
                  "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "Frank"
                  }
                },
                {
                  "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "Winona"
                  }
                },
              ],
              "parents": [
                {
                  "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "Frank"
                  }
                },
                {
                  "sys": {
                    "type": "Link",
                    "linkType": "Entry",
                    "id": "Anne"
                  }
                },
              ]
            }
          }
      }

In the example above we have added friends and parents to our person entry. Our C# class could be updated to reflect this, but perhaps we're only interested in the parents for some reason.

public class Person {
  public string Name { get; set; }
  public Profession Profession { get; set; }
  public IEnumerable<Person> Parents { get; set; }
}

Now, the entry with id "Frank" exists in both the friends and the parents collection, as the friends collection comes first in the structure it will be the "Frank" in that collection that will recieve the "$id" property, the next "Frank" in the parents collection will get the "$ref" property pointing to the original "Frank". However, and here's the crux, as the Person class doesn't contain a Friends property the object with the "$id" will never be deserialized and thus, when we come to the "$ref" property it will point to, you guessed it, null. Suddenly we end up with a couple of entries in our collection that are null, while others deserialize correctly, for no apparent reason.

The solution

The .NET SDK, thankfully, has a solution. There's a property called ResolveEntriesSelectively that can be set on your IContentfulClient. If this property is set to true the SDK will make sure to only set the "$id" and "$ref" on properties that exists on the passed in models. This property is not true by default as the SDK will be using reflection on the passed in classes to figure out which properties exist and this, of course, comes with a slight performance hit. This performance hit is in almost all cases negligible, but should still be a conscious decision.

With ResolveEntriesSelectively=true the example above would work just fine, as the "$id" would end up with the "Frank" in the parents collection instead of in the friends as the Person class doesn't contain a property named Friends.