Code Discussion

At this point, if you followed the steps in Get Started, you might have some more questions about how the code works. In this topic, we discuss the rational behind how categories are defined in Scrapbook101 and how C# objects are used to model both category and items.

Categories

Scrapbook101 items are described by a name/value pairs such as title, id, and category. There are also objects that contain child name/value pairs. For example, assets is an object that contains name/value pairs with the names name and size. See item document for more information.

Category values (category value) can be one of a fixed number of string values (“Books”, “Events”, etc.). Each category has a fixed number of associated fields as described in category document. The category fields (categoryField) object contains different name/value pairs that depend on the selected category.

The advantages of a nested structure (top level name/value pairs and nested name/value pairs defined in an object) is that it is easier to read and allows for more targeted searching because of the controlled category field taxonomy. The disadvantage of the nested structure is that it introduces more complexity in code because additional objects such as the Category.cs object are needed to track the nested structure.

An obvious question is if there another way to handle categories? Can the JSON structure be flattened? Consider an implementation of Scrapbook101 where the category document is not used, and category and categoryFields are not controlled by a schema but are allowed to be added or not. In this case, category values might be “Book”, “Books”, “BooksRead”, etc., that is, values are not governed by a fixed set of choices. This is certainly easier implementation-wise with less complicated class structures in code, but it becomes harder to have reliable search results.

Another consideration in choosing a JSON structure - choosing a schema - is determining which name/value pairs (fields) belong at the item-level (first-level) or as category fields (nested, second-level). Here are some rough guidelines for determining what fileds belong at the category level and which belong at the item level.

Models

There are three model files:

In the Item.cs and Category.cs classes, note the use of the Newtonsoft Json.NET JsonProperty annotations that allow the use of lowercase names for data fields in JSON (e.g., “assetPath”) and camelcase for data fields in code (e.g., “AssetPath”).

Finally, recall how our Scrapbook101 categories can contain name/value pairs (fields) with the same name. For example, a book and film item both have a synopsis field. Instead of defining multiple properties in code that have the same name “Synopsis”, we instead define one property that can be used for any category that includes a synopsis field. In Category.cs we define a CategoryFields class with all possible category fields, and allow indexing by name (this) so that just the fields for a given category are included with a Scrapbook101 are used.

public class Category
{
    [JsonProperty(PropertyName = "categories")]
    public List<CategoryItem> Categories { get; set; }
}
public class CategoryItem
{
    [JsonProperty(PropertyName = "categoryFields")]
    public CategoryFields CategoryFields { get; set; }
}
public class CategoryFields
{
    [JsonIgnore]
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value); }
    }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "synopsis")]
    public string Synopsis { get; set; }
}