Appearance
Are you an LLM? You can read better optimized documentation at /core_features/models.md for this page in Markdown format
Models
This document provides a detailed technical overview of the C# models used in TheExampleApp. These models are fundamental to the application's architecture, serving as the bridge between the Contentful headless CMS and the ASP.NET Core backend. They provide a strongly-typed representation of content, enabling robust and maintainable integration.
Content models
The application's content is managed in Contentful, and the C# models located in the TheExampleApp.Models namespace are designed to be direct one-to-one mappings of the Contentful content types. The contentful.aspnetcore SDK is responsible for deserializing the JSON responses from the Contentful Delivery API into instances of these C# classes.
This mapping is crucial for providing type safety and IntelliSense support throughout the application, from data retrieval in the controllers to data presentation in the Razor views. For a deeper understanding of how the SDK is configured and how it resolves these types, please refer to the Contentful Integration documentation.
Core content models
These models represent the primary content structures of the application. They are the top-level content types that define pages, courses, and their constituent parts.
Course
The Course model represents the structure for an educational course. It aggregates various pieces of information, including metadata, descriptive content, and linked entries for lessons and categories.
csharp
// TheExampleApp/Models/Course.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents
/// </summary>
public class Course
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the course.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The slug for the course.
/// </summary>
public string Slug { get; set; }
/// <summary>
/// The image for the course.
/// </summary>
public Asset Image { get; set; }
/// <summary>
/// The short description of the course.
/// </summary>
public string ShortDescription { get; set; }
/// <summary>
/// The description of the course.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The duration of the course in minutes.
/// </summary>
public int Duration { get; set; }
/// <summary>
/// The skill level required to complete the course.
/// </summary>
public string SkillLevel { get; set; }
/// <summary>
/// The lessons this course contain.
/// </summary>
public List<Lesson> Lessons { get; set; }
/// <summary>
/// The categories this course belongs to.
/// </summary>
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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Key Properties:
| Property | Type | Description |
|---|---|---|
Sys | SystemProperties | Contentful-provided metadata, including the entry ID. See Base models for more details. |
Image | Asset | A linked asset from Contentful. The Asset class is part of the SDK and contains properties like Url, Title, and Description for the image file. |
Description | string | A text field that likely contains Markdown. The application uses the Markdig library to parse this into HTML before rendering. |
Lessons | List<Lesson> | A reference field in Contentful linking to multiple Lesson entries. The SDK resolves these linked entries into a strongly-typed list. |
Categories | List<Category> | A reference field linking to Category entries, allowing for many-to-many relationships between courses and categories. |
Lesson
The Lesson model defines the structure of an individual lesson within a course. It employs a modular content strategy, where the body of the lesson is composed of a list of different module types.
csharp
// TheExampleApp/Models/Lesson.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents a lesson.
/// </summary>
public class Lesson
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the lesson.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The slug of the lesson.
/// </summary>
public string Slug { get; set; }
/// <summary>
/// The modules that makes up the lesson.
/// </summary>
public List<ILessonModule> Modules { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
The List<ILessonModule> Modules property is the most significant part of this model. It allows content editors to build a lesson by assembling various content blocks (modules) in any order. See the Module models section for details on how this polymorphism is achieved.
Category
The Category model is a simple taxonomy structure used to group and filter courses.
csharp
// TheExampleApp/Models/Category.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents a category.
/// </summary>
public class Category
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the category.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The slug for the category.
/// </summary>
public string Slug { get; set; }
/// <summary>
/// The description of the category.
/// </summary>
public string Description { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Layout
The Layout model enables the creation of generic, content-managed pages (e.g., a homepage or an "About Us" page). Similar to the Lesson model, it uses a list of modules to define its content, providing a flexible, component-based page-building experience.
csharp
// TheExampleApp/Models/Layout.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents a layout.
/// </summary>
public class Layout
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the layout.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The slug of the layout.
/// </summary>
public string Slug { get; set; }
/// <summary>
/// The modules that make up the layout.
/// </summary>
public List<ILayoutModule> ContentModules { get; set; }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Module models
The application's modular content architecture is enabled by a set of interfaces and corresponding concrete classes. This design pattern allows collections of heterogeneous content types (e.g., a list containing a hero image, then a text block, then a course highlight) to be represented in a single, strongly-typed list.
The foundation of this system is the IModule interface and its derivatives.
csharp
// TheExampleApp/Models/IModule.cs
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Base interface to mark which classes can be used as modules.
/// The Sys property is required for the SDK to identify the entry.
/// </summary>
public interface IModule
{
SystemProperties Sys { get; set; }
}
/// <summary>
/// Marker interface for modules that can be used within a Lesson.
/// </summary>
public interface ILessonModule : IModule
{
}
/// <summary>
/// Marker interface for modules that can be used within a generic Layout.
/// </summary>
public interface ILayoutModule : IModule
{
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Key Concepts:
IModule: This is the base interface for all content blocks. Its single requirement, theSystemProperties Sysproperty, is essential. When the Contentful SDK encounters a linked entry in a collection, it uses theSys.ContentType.SystemProperties.Idto determine which C# class to deserialize the entry into.ILessonModule&ILayoutModule: These are "marker interfaces." They inherit fromIModulebut add no new members. Their purpose is to provide compile-time safety and semantic clarity, ensuring that only appropriate modules can be added to aLessonor aLayout. For example, aCodeSnippetmodule might implementILessonModule, while aHeroImagemodule might implementILayoutModule. A genericCopymodule could implement both.
Example Module Implementations (Hypothetical):
Based on the summary, concrete module classes would look like this:
csharp
// Represents a block of text, usable in both layouts and lessons.
public class Copy : ILayoutModule, ILessonModule
{
public SystemProperties Sys { get; set; }
public string Title { get; set; }
public string Body { get; set; } // Markdown-enabled text field
}
// Represents a large hero image, typically for layouts.
public class HeroImage : ILayoutModule
{
public SystemProperties Sys { get; set; }
public string Headline { get; set; }
public Asset BackgroundImage { get; set; }
}
// Represents a formatted code snippet, specific to lessons.
public class CodeSnippet : ILessonModule
{
public SystemProperties Sys { get; set; }
public string Language { get; set; } // e.g., "csharp", "javascript"
public string Code { get; set; }
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Developer Gotcha: For this polymorphic deserialization to work, you must register a custom
IContentTypeResolverwith theContentfulClient. This resolver maps the Contentful Content Type ID (a string likecopyorheroImage) to the corresponding C#System.Type(e.g.,typeof(Copy)). Without this registration, the SDK will not know how to populate theList<ILessonModule>andList<ILayoutModule>collections. See the/architecture/contentful_integration.mdfor implementation details.
Base models
These models and properties form the foundational infrastructure upon which the content models are built.
SystemProperties
Every model that maps to a Contentful entry includes the public SystemProperties Sys { get; set; } property. This is not a custom application model but a class provided by the Contentful.Core.Models namespace. It is automatically populated by the SDK and contains essential metadata about the entry.
Commonly Used Sys Properties:
Sys.Id: The unique identifier for the entry.Sys.CreatedAt: The timestamp when the entry was created.Sys.UpdatedAt: The timestamp of the last update.Sys.ContentType.SystemProperties.Id: The ID of the content type (e.g., "course", "lesson"). This is critical for type resolution.
BasePageModel
While the source code is not provided, the application summary indicates the use of a BasePageModel. In an ASP.NET Core application using Razor Pages, this class would likely inherit from the framework's PageModel and serve as a base for all other page models in the application.
Its purpose is to reduce boilerplate and provide common functionality across all pages. Responsibilities might include:
- Holding shared layout data (e.g., main navigation, footer content).
- Defining common page metadata properties (e.g.,
SeoTitle,SeoDescription). - Injecting common services (like the
IContentfulClient) via its constructor for use by derived page models.
This pattern is a standard practice for keeping Razor Page models clean and adhering to the DRY (Don't Repeat Yourself) principle. For more information on the application's use of Razor Pages and Views, see the Razor Pages and Views documentation. The final rendering of content is detailed in the Content Display guide.