Appearance
Are you an LLM? You can read better optimized documentation at /api_reference/configuration.md for this page in Markdown format
Configuration classes
This document provides detailed API documentation for the configuration classes within the TheExampleApp.Configuration namespace. These classes are responsible for managing application state, handling cross-cutting concerns via middleware, and configuring services like content delivery and localization. They are primarily registered and consumed via the application's dependency injection container. For more information on service registration, see the Service Configuration and Dependency Injection documentation.
Breadcrumbs / IBreadcrumbsManager
This feature provides dynamic breadcrumb generation based on the current request URL. It consists of ASP.NET Core middleware (Breadcrumbs), a manager class for in-controller modifications (BreadcrumbsManager), and a data model (Breadcrumb).
Implementation Details
The Breadcrumbs class is implemented as middleware that intercepts each HTTP request.
- Path Parsing: It splits the request path (e.g.,
/courses/hello-world/) into segments (courses,hello-world). - Home Crumb: It always adds a "Home" breadcrumb pointing to the root (
/). - Segment Processing: For each segment, it creates a
Breadcrumbobject.- The label is derived from the path segment (e.g., "hello-world" becomes "hello world").
- It attempts to localize the label by looking for a corresponding key (e.g.,
coursesLabel) in the localization files viaIViewLocalizer. - The path is constructed cumulatively (e.g.,
/courses, then/courses/hello-world).
- Context Storage: The final list of
Breadcrumbobjects is stored inHttpContext.Items["breadcrumbs"]for the duration of the request.
The BreadcrumbsManager can be injected into controllers or Razor Pages to modify the generated breadcrumbs before the view is rendered. This is particularly useful for replacing slug-based labels (e.g., "hello-world") with human-readable titles fetched from the CMS (e.g., "Hello World!").
Registration
The middleware is added to the ASP.NET Core pipeline in Startup.cs using the provided extension method.
csharp
// In Startup.Configure(IApplicationBuilder app)
app.UseBreadcrumbs();1
2
2
API Reference
Breadcrumbs (Middleware)
This class is not intended for direct use outside the middleware pipeline. Its Invoke method contains the core logic.
csharp
// File: TheExampleApp/Configuration/Breadcrumbs.cs
public async Task Invoke(HttpContext context)
{
var path = context.Request.Path;
var parts = path.ToString().Split("/",StringSplitOptions.RemoveEmptyEntries);
var items = new List<Breadcrumb>();
// Always add a home breadcrumb, localized.
items.Add(new Breadcrumb { Label = _localizer["homeLabel"].Value, Path = "/" });
var translations = _localizer.GetAllStrings(false);
foreach (var part in parts)
{
var label = part.Replace("-", " ");
// Attempt to find a localized version of the label.
if(translations.Any(c => c.Name == $"{LowerCaseFirstChar(label)}Label"))
{
label = _localizer[$"{LowerCaseFirstChar(label)}Label"].Value;
}
items.Add(new Breadcrumb { Label = label, Path = $"/{string.Join('/', parts.Take(Array.IndexOf(parts, part) + 1))}" });
}
// Store the generated breadcrumbs in the HttpContext for the current request.
context.Items["breadcrumbs"] = items;
await _next(context);
}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
IBreadcrumbsManager
Service to modify breadcrumbs after initial generation.
| Method | Description |
|---|---|
void ReplaceCrumbForSlug(string slug, string label) | Finds a breadcrumb whose label matches the slug and replaces it with the new label. |
Example Usage (in a Razor Page or Controller):
csharp
public class CoursePageModel : PageModel
{
private readonly IBreadcrumbsManager _breadcrumbsManager;
public CoursePageModel(IBreadcrumbsManager breadcrumbsManager)
{
_breadcrumbsManager = breadcrumbsManager;
}
public async Task<IActionResult> OnGetAsync(string slug)
{
var course = await _contentfulClient.GetEntryBySlug<Course>(slug);
// Replace the slug "hello-world" with the actual course title "Hello World!"
_breadcrumbsManager.ReplaceCrumbForSlug(slug, course.Title);
// ...
return Page();
}
}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
ContentfulOptionsManager / IContentfulOptionsManager
This manager class provides a mechanism to dynamically select ContentfulOptions at runtime. It allows the application to switch between the default credentials (from appsettings.json) and temporary credentials stored in the user's session. This is the cornerstone of the "deep linking" and settings override functionality.
Implementation Details
The ContentfulOptionsManager is registered as a scoped service. On instantiation, it receives the default ContentfulOptions (via IOptions<ContentfulOptions>) and an IHttpContextAccessor to access the current session.
OptionsProperty: The getter for this property first checks if aContentfulOptionsobject exists in the currentHttpContext.Session.- If found, it deserializes and returns the session-based options.
- If not found, it returns the default options loaded from the application's configuration.
IsUsingCustomCredentialsProperty: This boolean property compares the session options (if they exist) with the default options to determine if an override is active.
This design ensures that a single user's action (like using a preview link) does not affect other users of the application, as the override is scoped to their session.
API Reference
| Property | Type | Description |
|---|---|---|
Options | ContentfulOptions | (Get-only) Returns the active ContentfulOptions for the current request, prioritizing session-based options over application defaults. |
IsUsingCustomCredentials | bool | (Get-only) Returns true if the current request is using ContentfulOptions from the session that differ from the application defaults. |
csharp
// File: TheExampleApp/Configuration/ContentfulOptionsManager.cs
// The core logic resides in the Options property getter.
public ContentfulOptions Options {
get {
// Attempt to retrieve options from the current user's session.
var sessionString = _accessor.HttpContext.Session.GetString(nameof(ContentfulOptions));
if (!string.IsNullOrEmpty(sessionString))
{
// If session options exist, deserialize and return them.
return JsonConvert.DeserializeObject<ContentfulOptions>(sessionString);
}
// Otherwise, fall back to the default options from appsettings.json.
return _options;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Deeplinker
The Deeplinker is ASP.NET Core middleware designed to parse incoming requests for specific query string parameters that control Contentful API settings and other editorial features. It enables developers and content editors to generate URLs that configure the application on-the-fly.
Implementation Details
The middleware inspects the query string for the following parameters:
space_id,preview_token,delivery_token: If all three are present, it constructs a newContentfulOptionsobject. It performs validation on these credentials.- On success, the new options are serialized to JSON and stored in the user's session.
- On failure, validation errors are stored in the session, and the user is redirected to the
/settingspage to correct them.
api: Can be set tocpato force the use of the Contentful Preview API. This is stored in the session'sContentfulOptions.editorial_features: Can be set toenabledordisabledto toggle UI elements that link directly to the Contentful web app. The state is stored in the session key"EditorialFeatures".
This middleware works in tandem with ContentfulOptionsManager. Deeplinker writes to the session, and ContentfulOptionsManager reads from it, effectively applying the changes for the duration of the user's session.
Registration
The middleware is added to the ASP.NET Core pipeline in Startup.cs, typically after session middleware has been configured.
csharp
// In Startup.Configure(IApplicationBuilder app)
app.UseSession();
app.UseDeeplinks();1
2
3
2
3
API Reference
The Deeplinker class is middleware and not used directly. Its behavior is configured entirely by the query string parameters of an incoming request.
Example URL:
https://www.theexampleapp.com/?space_id=YOUR_SPACE_ID&delivery_token=YOUR_DELIVERY_TOKEN&preview_token=YOUR_PREVIEW_TOKEN&api=cpa&editorial_features=enabled1
This URL will configure the user's session to:
- Use the specified Contentful space and API keys.
- Force requests to the Contentful Preview API.
- Enable editorial feature UI elements.
LocalizationConfiguration / JsonViewLocalizer
JsonViewLocalizer is a custom implementation of the IViewLocalizer interface from Microsoft.AspNetCore.Mvc.Localization. It overrides the default RESX-based localization system to source translation strings from JSON files.
Implementation Details
- File-based Loading: The constructor takes an
IFileProviderand reads all files from the configured directory (e.g., aLocalizationfolder). It assumes a naming convention likeresources.en-US.json,resources.de-DE.json. - In-Memory Cache: Each JSON file is deserialized into a
Dictionary<string, string>and stored in a parent dictionary, keyed by culture name (e.g., "en-US"). This provides fast, in-memory lookups for the lifetime of the service. - Culture-Specific Lookups: Methods like
GetStringand the indexer (this[string name]) useCultureInfo.CurrentCultureto select the correct dictionary and retrieve the translated string. If a key or culture is not found, it gracefully falls back to returning the key itself.
Note: Several methods of the
IViewLocalizerandIHtmlLocalizerinterfaces, such asthis[string name, params object[] arguments]andWithCulture(CultureInfo culture), are not implemented and will throw aNotImplementedException. The current implementation focuses only on simple key-value string replacement.
API Reference
JsonViewLocalizer
| Member | Description |
|---|---|
this[string name] | Indexer that returns a LocalizedHtmlString for the given name based on the CultureInfo.CurrentCulture. Used directly in Razor views (e.g., @Localizer["myKey"]). |
GetAllStrings(bool includeParentCultures) | Returns all key-value pairs for the current culture as an IEnumerable<LocalizedString>. |
GetString(string name) | Returns a LocalizedString for the given name and current culture. |
csharp
// File: TheExampleApp/Configuration/LocalizationConfiguration.cs
// The constructor loads all JSON files from the provided path.
public JsonViewLocalizer(IFileProvider provider)
{
var files = provider.GetDirectoryContents("");
foreach (IFileInfo file in files)
{
using ( var sr = new StreamReader(file.CreateReadStream()))
{
var fileContents = sr.ReadToEnd();
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(fileContents);
// The culture is parsed from the filename, e.g., "resources.en-US.json" -> "en-US"
var fileName = Path.GetFileNameWithoutExtension(file.Name);
_items.Add(fileName.Substring(fileName.LastIndexOf('.') + 1), dictionary);
}
}
}
// The indexer provides easy access to localized strings in views.
public LocalizedHtmlString this[string name] => new LocalizedHtmlString(name, _items[CultureInfo.CurrentCulture.ToString()][name]);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ModulesResolver
Note: The source code for
ModulesResolverwas not provided in the input. The following description is based on its name and common architectural patterns when using a headless CMS like Contentful.
The ModulesResolver class is likely a service responsible for handling polymorphic deserialization of content modules fetched from Contentful.
In a headless CMS, a page is often composed of a list of different "module" or "block" types (e.g., a Hero Banner, a Text Block, an Image Gallery). When this data is fetched via an API, it arrives as a heterogeneous list of JSON objects. The ModulesResolver would inspect a discriminant field (e.g., sys.contentType.sys.id in Contentful's response) to determine which concrete C# class (e.g., HeroBanner, TextBlock) to deserialize the JSON object into.
This pattern allows for flexible, component-based page structures managed entirely within the CMS. The resolver is a critical piece of infrastructure that maps the CMS content model to the application's C# Models.
VisitedLessons / IVisitedLessonsManager
This manager provides a simple mechanism to track which lesson or course pages a user has visited. This state is persisted across requests using a browser cookie.
Implementation Details
- Cookie-based Storage: The manager uses a cookie named
ContentfulVisitedLessonsto store a semicolon-delimited string of visited lesson/course IDs. - Initialization: The constructor is injected with
IHttpContextAccessorto read the request's cookies. If theContentfulVisitedLessonscookie exists, its value is parsed into the publicVisitedLessonslist. - State Modification: The
AddVisitedLesson(string lessonId)method adds a new ID to the list and immediately updates the cookie on theHttpResponse. The cookie is set withHttpOnly = truefor security and has an expiration of 7 days.
This service is typically registered with a scoped lifetime so that a new instance is created for each request, ensuring the VisitedLessons list is always synchronized with the latest cookie data.
API Reference
IVisitedLessonsManager
| Member | Type | Description |
|---|---|---|
VisitedLessons | List<string> | (Get-only) A list of Contentful entry IDs for the lessons and courses that the user has visited during the cookie's lifetime. |
AddVisitedLesson | void | Adds the provided lessonId to the VisitedLessons list and updates the browser cookie. The list of IDs in the cookie is made unique to prevent redundant storage. |
csharp
// File: TheExampleApp/Configuration/VisitedLessons.cs
public class VisitedLessonsManager: IVisitedLessonsManager
{
private readonly string _key = "ContentfulVisitedLessons";
private readonly IHttpContextAccessor _accessor;
public List<string> VisitedLessons { get; private set; }
// The constructor reads the cookie on instantiation.
public VisitedLessonsManager(IHttpContextAccessor accessor)
{
VisitedLessons = new List<string>();
_accessor = accessor;
var cookie = _accessor.HttpContext.Request.Cookies[_key];
if (!string.IsNullOrEmpty(cookie))
{
VisitedLessons = new List<string>(cookie.Split(';', StringSplitOptions.RemoveEmptyEntries));
}
}
// This method adds an ID and updates the response cookie.
public void AddVisitedLesson(string lessonId)
{
VisitedLessons.Add(lessonId);
var options = new CookieOptions();
options.HttpOnly = true;
options.Expires = DateTime.Now.AddDays(7);
_accessor.HttpContext.Response.Cookies.Append(_key, string.Join(';', VisitedLessons.Distinct()), options);
}
}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
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