Appearance
Are you an LLM? You can read better optimized documentation at /models/lesson_modules.md for this page in Markdown format
Lesson modules
This document provides a detailed technical overview of the various content modules used to construct lessons within the application. These modules are the fundamental building blocks for all educational content.
Lesson content types
Lessons are not monolithic blocks of content. Instead, they are composed of an ordered sequence of distinct content modules. This modular approach, powered by a headless CMS (Contentful), allows for flexible and rich content creation. The application currently supports the following module types:
LessonCopy: For standard text-based content, supporting Markdown for rich formatting.LessonImage: For embedding images with optional captions.LessonCodeSnippets: A specialized module for displaying code examples in multiple programming languages.
Each of these modules is represented by a C# class that maps directly to a corresponding Content Type in Contentful. They are dynamically fetched and rendered on the lesson page.
LessonCopy
The LessonCopy module is the most common module type, used for displaying paragraphs of text, headings, lists, and other standard content.
Model Definition
The module is defined in TheExampleApp/Models/Lesson - Copy.cs. It is designed to be simple, containing only a title and a body.
csharp
// File: TheExampleApp/Models/Lesson - Copy.cs
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
public class LessonCopy : ILessonModule
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the module.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The body copy of the module.
/// </summary>
public string Copy { 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Implementation Details
Title: An optional string that is typically rendered as a sub-heading (<h2>or<h3>) for a section of the lesson.Copy: A string field containing the main content. The application uses the Markdig library (Markdig, v0.15.4) to parse this field as Markdown. This allows content authors to use standard Markdown syntax for formatting, which is then converted to HTML at render time.
LessonImage
The LessonImage module is used to embed visual aids within a lesson.
Model Definition
The model, defined in TheExampleApp/Models/Lesson - Image.cs, links to a Contentful asset and includes fields for a title and caption.
csharp
// File: TheExampleApp/Models/Lesson - Image.cs
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents a image module for a lesson.
/// </summary>
public class LessonImage : ILessonModule
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the module.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The image of the module.
/// </summary>
public Asset Image { get; set; }
/// <summary>
/// The caption of the image.
/// </summary>
public string Caption { 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
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
Implementation Details
Image: This property is of typeContentful.Core.Models.Asset. This is not a simple URL string. The Contentful SDK populates this with a full asset object, which includes the image URL, dimensions, file size, and other metadata. The corresponding partial view is responsible for extracting the URL from this object.Caption: A simple string for displaying text directly below the image. This field supports Markdown rendering via the Markdig library.
LessonCodeSnippets
This is a specialized module for presenting code examples, often used in technical tutorials. It allows a single module to contain the same code snippet written in multiple languages.
Model Definition
The model, defined in TheExampleApp/Models/Lesson - Code Snippets.cs, has a dedicated string property for each supported programming language.
csharp
// File: TheExampleApp/Models/Lesson - Code Snippets.cs
using Contentful.Core.Models;
namespace TheExampleApp.Models
{
/// <summary>
/// Represents a code snippets module for a lesson.
/// </summary>
public class LessonCodeSnippets : ILessonModule
{
/// <summary>
/// The system defined meta data properties.
/// </summary>
public SystemProperties Sys { get; set; }
/// <summary>
/// The title of the module.
/// </summary>
public string Title { get; set; }
/// <summary>
/// The Curl snippet.
/// </summary>
public string Curl { get; set; }
/// <summary>
/// The .NET snippet.
/// </summary>
public string DotNet { get; set; }
/// <summary>
/// The JavaScript snippet.
/// </summary>
public string Javascript { get; set; }
/// <summary>
/// The Java snippet.
/// </summary>
public string Java { get; set; }
/// <summary>
/// The Java for Android snippet.
/// </summary>
public string JavaAndroid { get; set; }
/// <summary>
/// The PHP snippet.
/// </summary>
public string Php { get; set; }
/// <summary>
/// The Python snippet.
/// </summary>
public string Python { get; set; }
/// <summary>
/// The Ruby snippet.
/// </summary>
public string Ruby { get; set; }
/// <summary>
/// The Swift snippet.
/// </summary>
public string Swift { 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
Implementation Details
The frontend is expected to render this module as a tabbed interface, allowing the user to switch between languages. The backend model simply acts as a data container.
| Property | Language |
|---|---|
Curl | cURL |
DotNet | .NET (C#) |
Javascript | JavaScript |
Java | Java |
JavaAndroid | Java (for Android) |
Php | PHP |
Python | Python |
Ruby | Ruby |
Swift | Swift |
The corresponding partial view (LessonCodeSnippets.cshtml) must contain the logic to generate the tab navigation and panels, likely using a client-side script for interactivity.
Module structure
All lesson modules adhere to a common structure, enabling them to be treated polymorphically by the application.
The ILessonModule Interface
While the interface definition is not shown, its usage implies it serves as a marker interface. All module classes (LessonCopy, LessonImage, etc.) implement ILessonModule. This allows them to be stored in a single collection within the parent Lesson model.
The Lesson Container
The Lesson model itself acts as the container for these modules. The Modules property is a list of ILessonModule objects, which the Contentful SDK populates based on the linked entries in the CMS.
csharp
// File: TheExampleApp/Models/Lesson.cs
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
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
Common Properties
Sys: An instance ofContentful.Core.Models.SystemProperties. This object is automatically populated by the SDK and contains metadata about the Contentful entry, such as its ID, version, creation date, and Content Type. It is invaluable for debugging.Title: A string property present on all modules. It serves as an optional heading for the module's content block.
For more information on the Contentful data structures, see Content Models.
Rendering lessons
The application uses a dynamic, convention-based approach to render the modules on a lesson page. This logic is centralized in the main Razor Page for lessons.
Dynamic Partial View Rendering
The core of the rendering logic is found in TheExampleApp/Pages/Courses/Lessons.cshtml. The page iterates through the Modules collection of the SelectedLesson and uses the type name of each module to select the appropriate partial view.
csharp
// File: TheExampleApp/Pages/Courses/Lessons.cshtml
<div class="lesson__modules">
@if (Model.SelectedLesson.Modules == null || Model.SelectedLesson.Modules.Count == 0)
{
@Html.Partial("NoContent")
}
else
{
// This loop dynamically renders each module
@foreach (var module in Model.SelectedLesson.Modules)
{
// Example: If module is a LessonCopy object, this calls
// Html.Partial("LessonCopy", module)
@Html.Partial(module.GetType().Name, module)
}
}
</div>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
How It Works
module.GetType().Namereturns the name of the C# class as a string (e.g.,"LessonCopy","LessonImage").@Html.Partial()is an ASP.NET Core helper that renders a partial view. It searches for a view file matching the provided name (e.g.,LessonCopy.cshtml) in standard locations, such as/Pages/Shared/.- The
moduleobject itself is passed as the model to the partial view, giving that view strongly-typed access to the module's properties.
This pattern is highly extensible. To add a new module type:
- Create a new C# model class that implements
ILessonModule. - Create a corresponding partial view in
/Pages/Shared/with a filename that matches the class name. - No changes are needed to the main
Lessons.cshtmlpage.
For more details on the view layer, see Shared Views.
Content authoring
For developers to work effectively, it is crucial to understand how content is structured in Contentful. Each C# model corresponds directly to a Content Type in the CMS.
Lesson Content Type: This is the main entry for a lesson. It contains fields like
titleandslug, and most importantly, a Many References field. This reference field is configured to accept entries of the various module content types (LessonCopy,LessonImage, etc.). The order of the linked modules in this field dictates their render order on the page.LessonCopy Content Type:
title: Short Text field.copy: Long Text field. Crucially, this field should be configured to enable Markdown.
LessonImage Content Type:
title: Short Text field.image: A Single Media reference field, linking to an asset in the Contentful media library.caption: Short Text field.
LessonCodeSnippets Content Type:
title: Short Text field.- Each language (
curl,dotNet,javascript, etc.) is a separate Long Text field. These fields should be configured for plain text to preserve code formatting.
Gotcha: The Contentful SDK relies on the Content Type ID in the CMS matching the C# class name (or a custom mapping) for correct deserialization. Ensure these IDs are set correctly (e.g., the Content Type for LessonCopy should have an ID of lessonCopy). Refer to the Contentful SDK documentation for details on type mapping.