Appearance
Are you an LLM? You can read better optimized documentation at /models/content_models.md for this page in Markdown format
Content models
Overview
This document provides a detailed technical reference for the C# data models that represent content stored in the Contentful headless CMS. These models are the primary mechanism for transferring data from the Contentful API into the ASP.NET Core application, enabling strong typing, business logic encapsulation, and seamless integration with Razor views.
Understanding these models is crucial for any developer working on features that consume or display content, as they form the contract between the CMS and the application code. For a higher-level view of how the application connects to and queries Contentful, please see the Contentful Integration Architecture documentation.
Model Purpose: POCOs for Contentful Integration
The application employs a Plain Old C# Object (POCO) pattern to represent Contentful content types. Each C# class in the TheExampleApp.Models namespace corresponds directly to a content type defined in the Contentful space.
This approach offers several key advantages:
- Strong Typing: It replaces dynamic JSON objects with strongly-typed C# classes, providing compile-time checking and robust IntelliSense support in Visual Studio.
- Automated Deserialization: The
contentful.aspnetcoreSDK automatically deserializes the JSON responses from the Contentful Delivery API into instances of these POCOs. This eliminates the need for manual JSON parsing. - Clean Architecture: It cleanly separates the data structure (the models) from the application logic (controllers, services) and presentation (Razor views).
The contentful.aspnetcore client is configured to map Contentful content type IDs to these specific C# classes using a ContentTypeResolver, as demonstrated in the application's BasePageModel.
csharp
// File: TheExampleApp/Models/BasePageModel.cs
public class BasePageModel : PageModel
{
protected readonly IContentfulClient _client;
public BasePageModel(IContentfulClient client)
{
_client = client;
// The resolver maps Contentful Type IDs to C# classes.
_client.ContentTypeResolver = new ModulesResolver();
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Course Model
The Course model is the central content entity in the application, representing an educational course. It aggregates various pieces of information, including descriptive text, metadata, and relationships to lessons and categories. This model is fundamental to the Course Management feature.
csharp
// File: TheExampleApp/Models/Course.cs
using Contentful.Core.Models;
using System.Collections.Generic;
namespace TheExampleApp.Models
{
public class Course
{
public SystemProperties Sys { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public Asset Image { get; set; }
public string ShortDescription { get; set; }
public string Description { get; set; }
public int Duration { get; set; }
public string SkillLevel { get; set; }
public List<Lesson> Lessons { get; set; }
public List<Category> Categories { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Properties
| Property | Type | Description |
|---|---|---|
Sys | SystemProperties | Contentful-provided metadata. See SystemProperties and Metadata section below. |
Title | string | The main display title of the course. |
Slug | string | A URL-friendly identifier for the course, used in routing. |
Image | Asset | A reference to a Contentful asset, typically the course's banner image. See Asset Handling. |
ShortDescription | string | A brief, one-sentence summary of the course, often used in list views or cards. |
Description | string | The full, detailed description of the course. This field likely contains Markdown, which is rendered by the Markdig library. |
Duration | int | The estimated time to complete the course, in minutes. |
SkillLevel | string | The target skill level (e.g., "Beginner", "Intermediate", "Advanced"). This is likely a text field in Contentful with validation rules. |
Lessons | List<Lesson> | A one-to-many relationship to the Lesson entries that comprise the course. See Relationships. |
Categories | List<Category> | A many-to-many relationship to the Category entries the course belongs to. See Relationships. |
Lesson Model
The Lesson model represents a single unit of learning within a Course. Its most important feature is the Modules property, which allows for a flexible and composable content structure.
csharp
// File: TheExampleApp/Models/Lesson.cs
using Contentful.Core.Models;
using System.Collections.Generic;
namespace TheExampleApp.Models
{
public class Lesson
{
public SystemProperties Sys { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public List<ILessonModule> Modules { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Properties
| Property | Type | Description - |
|---|---|---|
Sys | SystemProperties | Contentful-provided metadata. - |
Title | string | The title of the lesson. - |
Slug | string | A URL-friendly identifier for the lesson, used in routing. - |
Modules | List<ILessonModule> | A polymorphic list of content blocks that make up the lesson. This allows a lesson to be composed of various types of content (e.g., text blocks, code snippets, images). For a full breakdown of available modules, see the Lesson Modules documentation. |
Category Model
The Category model is a simple taxonomy object used to group and classify Course entries.
csharp
// File: TheExampleApp/Models/Category.cs
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
public class Category
{
public SystemProperties Sys { get; set; }
public string Title { get; set; }
public string Slug { get; set; }
public string Description { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Properties
| Property | Type | Description |
|---|---|---|
Sys | SystemProperties | Contentful-provided metadata. |
Title | string | The display name of the category. |
Slug | string | A URL-friendly identifier for the category, used for filtering and creating category-specific landing pages. |
Description | string | A short description of the category's topic. |
SystemProperties and Metadata
Every model that maps to a Contentful entry includes a Sys property of type Contentful.Core.Models.SystemProperties. This property is automatically populated by the SDK and provides critical metadata about the entry. It is not editable content but is essential for the application's logic.
Key fields within SystemProperties include:
Sys.Id: The unique identifier for the entry (e.g.,4sBqW1V3y4A44Wk2y08U8U).Sys.Type: The type of the entity, which is always "Entry" for content models.Sys.ContentType.SystemProperties.Id: The ID of the content type (e.g., "course", "lesson"). This is crucial for theContentTypeResolver.Sys.CreatedAt: The timestamp when the entry was created.Sys.UpdatedAt: The timestamp of the last modification.Sys.Locale: The locale of the fetched entry (e.g., "en-US").
Developer Gotcha: Do not attempt to set the Sys property manually. It is managed entirely by the Contentful SDK during deserialization. Accessing Sys.Id is the standard way to uniquely identify an entry within the application.
Asset Handling
Media files such as images, videos, and documents are handled via the Contentful.Core.Models.Asset class. In our models, this is demonstrated by the Image property on the Course class.
csharp
// From TheExampleApp/Models/Course.cs
public Asset Image { get; set; }1
2
2
The Asset object contains metadata about the file as well as the file itself. The most important properties for rendering are nested within the File property:
Asset.Title: The internal title of the asset in Contentful.Asset.Description: The description of the asset.Asset.File.Url: The protocol-agnostic URL of the asset (e.g.,//images.ctfassets.net/.../image.png). This is the property you will use insrcattributes.Asset.File.Details.Image.WidthandAsset.File.Details.Image.Height: Dimensions of the image, if applicable.Asset.File.ContentType: The MIME type of the file (e.g.,image/jpeg).
Example usage in a Razor view:
html
@* Example of rendering a course image *@
@if (Model.Course.Image != null)
{
<img src="@Model.Course.Image.File.Url" alt="@Model.Course.Image.Title" />
}1
2
3
4
5
2
3
4
5
Relationships
The models define how content types are linked to each other. The Contentful SDK resolves these links into nested objects, provided the API query includes the linked entries.
One-to-Many Relationship
The relationship between a Course and its Lessons is a classic one-to-many link. A course contains multiple lessons, but each lesson belongs to one course.
- Model:
Course.cshas apublic List<Lesson> Lessons { get; set; }. - Implementation: In Contentful, this is a "Reference" field on the "Course" content type, configured to accept multiple entries of the "Lesson" type.
Many-to-Many Relationship
The relationship between Course and Category is many-to-many. A course can be in multiple categories, and a category can contain multiple courses.
- Model:
Course.cshas apublic List<Category> Categories { get; set; }. - Implementation: This is also a multi-reference field in Contentful. The reverse relationship (finding all courses for a category) is achieved by querying for
Courseentries where thefields.categories.sys.idmatches a specific category ID.
Polymorphic Relationship (Modules)
The most advanced relationship is the polymorphic structure used for lesson content. The Lesson.Modules property is a list of an interface type, ILessonModule.
csharp
// File: TheExampleApp/Models/IModule.cs
public interface IModule
{
SystemProperties Sys { get; set; }
}
public interface ILessonModule : IModule { }1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- Model:
Lesson.cshas apublic List<ILessonModule> Modules { get; set; }. - Implementation: This allows a
Lessonto contain a mixed list of different content block types (e.g.,CodeBlock,TextBlock), as long as each corresponding model implements theILessonModuleinterface. TheContentTypeResolveris responsible for instantiating the correct concrete class based on the content type ID of the linked entry. - Further Reading: For a detailed list of concrete module implementations, refer to the Lesson Modules and Layout Modules documentation.
Important: When querying for entries with linked content (like a Course and its Lessons), you must specify the include level in your Contentful API call. An include level of 1 will fetch the course and its direct links (lessons, categories). An include of 2 will also fetch the links within those lessons (the modules). Failing to set an adequate include level will result in null or empty lists for your relationship properties. See the Contentful Integration Architecture for query examples.