Retrieve page content
Web page content is stored in the database and edited through the administration interface using the content tree in website channel applications.
The Xperience API allows you to work with pages using:
- Generated content type classes (recommended) – classes generated by the system that allow you to work with content type fields using strongly-typed objects. These classes also allow access to all general page data (page title, ID, GUID, creation date, publish date, etc.).
- Custom data transfer objects (advanced use case) – using custom DTOs grants you control over the mapping logic. See Map using GetResult<TModel>
The implementation and complexity of the retrieval and management code depend on your preferences and project requirements, and can range from simple method calls within controller actions to custom solutions utilizing repository and service patterns. Install the sample Dancing Goat project to view a reference implementation.
Retrieve page data
To retrieve web page content, use the following services from CMS.ContentEngine
and CMS.Websites
namespaces:
ContentItemQueryBuilder
class with theForWebsite
query parametrization method – to create and parametrize a content item query specifically for retrieving website data. TheForWebsite
query parameter has the following properties:websiteChannelName
– code name of the website channel from which the pages are retrieved. You can use current channel context to retrieve this value.pathMatch
– a parameter of typePathMatch
used to limit the retrieved pages based on their positon in the website’s content tree. See Filter pages based on content tree structure for more information.includeUrlPath
– indicates if the URLs of pages and content item assets are fetched as well. Defaults totrue
.
IContentQueryExecutor
interface and itsGetMappedWebPageResult
method – to execute a page query specified by the builder and map the results to the model class.- To retrieve correct version of pages in preview mode and Page Builder, modify the query execution by configuring the
ContentQueryExecutionOptions
.
- To retrieve correct version of pages in preview mode and Page Builder, modify the query execution by configuring the
// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;
public async Task PageRetrieval()
{
// Configures the query builder
var builder = new ContentItemQueryBuilder()
.ForContentType(
// Scopes the query to pages of the 'My.ArticlePage' content type
"My.ArticlePage",
config => config
// Retrieves pages only from the specified channel and path
.ForWebsite(
"MyWebsiteChannel",
PathMatch.Children("/Articles"))
// Retrieves only English variants of pages
).InLanguage("en");
// Executes the query and stores the data in generated 'ArticlePage' models
IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(builder);
// Displays the page data
foreach(var page in pages)
{
Console.WriteLine(page.ArticleTitle);
Console.WriteLine(page.ArticlePageSummary);
}
}
Retrieve multilingual page data
To retrieve web page content in a specific language, use the InLanguage method and as a parameter provide the language code name as specified in the Languages application.
// Creates a query to retrieve pages in the Spanish language
var builder = new ContentItemQueryBuilder()
.ForContentType(
// ...
).InLanguage("es");
If you omit the method and don’t specify a language, the query returns results in the primary language of the website channel.
Pages in fallback language
If the desired language variant of a page doesn’t exist, the query returns the page data in the fallback language, if fallbacks are configured.
Filter pages based on content tree structure
You can set the query to only include pages from a certain section of the content tree or omit pages from a section using the PathMatch
parameter of the ForWebsites
query parametetrization method. PathMatch expressions can be combined to more accurately specify what pages are included in the query.
Single
– only retrieves a single page that corresponds to the specified tree path.- E.g.,
PathMatch.Single(path: "/Articles/Coffee_processing_techniques")
- E.g.,
Children
– recursively retrieves all children of a specified parent page, excluding the parent page from the query. You can also specify a nesting level to limit the depth of recursion.- E.g.,
PathMatch.Children(path: "/Articles", nestingLevel: 3)
- E.g.,
SkipChildren
– recursively exclude all children of a specified parent page from the query, except for the parent page. You can also specify a nesting level to limit the depth of recursion.- E.g.,
PathMatch.SkipChildren(path: "/Articles/Coffee", nestingLevel: 3)
- E.g.,
Section
– recursively retrieves all children of a specified parent page, including the parent page in the query. You can also specify a nesting level to limit the depth of recursion.- E.g.,
PathMatch.Section(path: "/Articles", nestingLevel: 3)
- E.g.,
SkipSection
– recursively exclude all children and the specified parent page from the query. You can also specify a nesting level to limit the depth of recursion.- E.g.,
PathMatch.SkipSection(path: "Articles/Coffee", nestingLevel: 3)
- E.g.,
Combine PathMatch expressions
You can combine multiple PathMatch
expressions by passing an array as the argument to the ForWebsite
method.
var builder = new ContentItemQueryBuilder()
.ForContentType(
"My.ArticlePage",
config => config
.ForWebsite(
websiteChannelName: "MyWebsiteChannel",
pathMatches: new PathMatch[]{
PathMatch.Children("/Articles"),
PathMatch.SkipSection("/Articles/Coffee_processing_techniques")
}
)
);
Filter pages based on tags
You can limit the retrieval query to only retrieve pages with the specified tags using the WhereContainsTags
content item query parametrization method.
See Retrieve content items for more information.
Page security configuration
Pages can be secured to allow access only to authenticated users. You can filter out secured pages during retrieval by passing the appropriate bool value to the IncludeSecuredItems
property of the ContentQueryExecutionOptions
and providing them to the query executor.
// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;
// Information about whether to include secured items in the query execution passed from the caller
public async Task PageRetrieval(bool includeSecuredItems)
{
// Configures the query builder
var builder = new ContentItemQueryBuilder()...;
// Configures the query options for the query executor
var queryOptions = new ContentQueryExecutionOptions()
{
IncludeSecuredItems = includeSecuredItems
};
// Executes the query and stores the data in generated 'ArticlePage' models
IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(
builder: builder,
options: queryOptions);
}
The secured state of a retrieved page is indicated by its page.SystemFields.ContentItemIsSecured
property. You can use this property to display information to visitors accordingly.
For example, you can pass the page’s ContentItemIsSecured
property to a model and display an appropriate message to visitors.
// In this case, the 'ContentItemIsSecured' is mapped to the 'IsSecured' property of this view model
@if (model.IsSecured && !User.Identity.IsAuthenticated)
{
<p>
Sign in to access this page
</p>
}
An alternative popular practice is to display a blurred teaser image overlaid with a lock to indicate elevated permission requirements.
You can check whether the current ClaimsPrincipal
is authenticated via User.Identity.IsAuthenticated
. If unauthenticated visitors attempt to access a secured page, the server returns HTTP 403 Forbidden. ASP.NET Identity can be configured to automatically redirect such requests to another location on the website (typically a registration or sign in page) via AccessDeniedPath
.
builder.Services.ConfigureApplicationCookie(options =>
{
// Responses that would otherwise return 403 are instead redirected to <domain>/account/signin
options.AccessDeniedPath = new PathString("/account/signin");
});
Work with retrieved page data
You can access various types of data from retrieved page objects:
- Content type fields – the data that is editable in a page’s Content view mode. The set of available fields is configurable via the field editor.
- System fields – available under the
SystemFields
property of the retrieved page objects. AccessWebPage*
fields for web page data andContentItem*
for data of the underlying content item. - Page URL – see Get page URLs.
// Retrieves a page
var page = (await executor.GetMappedWebPageResult<Article>(builder)).FirstOrDefault();
// Accesses the ID of the parent
var parentId = page.SystemFields.WebPageItemParentID;
// Accesses the code name of the page object
var pageName = page.SystemFields.WebPageItemName;
Access page field data
The fields available in a page’s Content view mode are specific to its content type. You can see the fields that each content type uses:
- In Content types (application) → edit a content type → Fields tab
- In the corresponding <namespace>_<content_type_name> database table
You can access specific fields of a content type directly using strongly typed properties when using generated content type classes:
// Retrieves a page
var page = (await executor.GetMappedWebPageResult<Article>(builder)).FirstOrDefault();
// Accesses the 'Text' field of the page
var pageText = page.ArticlePageText;
// Accesses the 'Teaser' field of the page
var pageImage = page.ArticlePageTeaser.FirstOrDefault();
Resolving HTML tags and relative URLs
Fields which are populated by the Rich text editor form component may contain HTML tags and relative links. To ensure that the content is displayed correctly when rendered in Razor views, use the Html.Raw
method, which disables HTML encoding for the values.
@Html.Raw(Model.<RichTextFieldProperty>)
Automatic URL resolving
The system provides page output filtering functionality that automatically resolves all virtual relative URLs to their absolute form. This filter ensures that links added by content editors into page content work correctly, even if you do not explicitly handle URL resolving in your code.
Date and time fields
DateTime
fields and system properties of retrieved pages always have values in the time zone of the server where the application is running. If you wish to display values in a different time zone (e.g., in a website visitor’s local time), perform a time conversion using the standard .NET API.
Get page URLs
Pages in the content tree of Xperience websites can have their live site URLs generated by the system through content tree-based routing or entered by marketers as a vanity URL. This allows content editors to create new pages or adjust the URLs of existing ones in the administration interface, without the need to update and redeploy the application. The URL that is returned by the retriever is whichever URL is selected as the canonical (system URLs by default).
You may need to get the URLs of retrieved pages in various scenarios, such as rendering navigation menus or other page links, performing redirects, etc.
To get the URL of a page in general code, use any of the Retrieve
method overloads of the IWebPageUrlRetriever
interface (available in the CMS.Websites
namespace). The most common usages might include:
// An instance of IWebPageUrlReriever (e.g., obtained via dependency injection)
private readonly IWebPageUrlRetriever webPageUrlRetriever;
// A page retrieved using the content query
ArticlePage article;
// Id of a web page retrieved previously
int webPageItemId;
// Retrieves URL data of a page in a specific language using the whole page and language code
WebPageUrl url1 = await webPageUrlRetriever.Retrieve(article, "en")
string url1_relative = url1.RelativePath;
string url1_absolute = url1.AbsoluteUrl;
// Retrieves URL data of a page in a specific language using the page id and language code
WebPageUrl url2 = await webPageUrlRetriever.Retrieve(webPageItemId, "en")
string url2_relative = url1.RelativePath;
string url2_absolute = url1.AbsoluteUrl;
Retrieved URLs are always returned in lower case without a trailing slash. You can modify some behavior of retrieved URLs using the following options and the .NET options pattern:
WebPageUrlRetrieverOptions
– Allows you to change the cache duration. The URLs are by default cached for 24 hours.UrlResolveOptions
– Allows you to specify whether SSL protocol should be included when retrieving absolute URLs. By default,https
URLs are returned.
var builder = WebApplication.CreateBuilder(args);
// ...
// Sets the cache duration to 60 minutes
builder.Services.Configure<WebPageUrlRetrieverOptions>(options => options.MaximumUrlCacheDuration = TimeSpan.FromMinutes(60));
// Includes SSL in absolute URLs
builder.Services.Configure<UrlResolveOptions>(options => options.UseSSL = false);
The relative path to a page returned by the Retrieve
method can be resolved to an application absolute path at runtime (for example using the UrlHelper.Content method).
@using Microsoft.AspNetCore.Mvc
<!-- Relative URL of the article is passed through the AricleUrl model property -->
<a href="@Url.Content(Model.ArticleUrl)">Visit the Article!</a>
Access context of the current request
Xperience by Kentico provides interfaces that help you access information about the current context.
Access context of the current channel
To retrieve information about the website channel context of the current request, use an instance of the IWebsiteChannelContext
interface (e.g., obtained via dependency injection) from the CMS.Websites.Routing
namespace.
Access the following properties:
WebsiteChannelID
– the ID of the current website channel.WebsiteChannelName
– code name of the current website channel.IsPreview
– a boolean value that, iftrue
, signifies whether the current request is made in preview (Page Builder or the preview mode in a website channel application).
Access current preferred language
To retrieve the preferred language of the current request, use the Get
method of the IPreferredLanguageRetriever
interface (e.g., obtained via dependency injection) .
Note that the preferred language of the request can be different from the actual language of the retrieved content. For example, if language variant of a page does not exist in the preferred language, fallback language variant is retrieved.
// An instance of IPreferredLanguageRetriever (e.g., obtained via dependency injection)
private readonly IPreferredLanguageRetriever preferredLanguageRetriever;
// Retrieves the code name of the preferred language
string languageName = preferredLanguageRetriever.Get();
Retrieve pages for preview
Whenever you work with pages within a website channel application, the system retrieves a given page from the database. Therefore, in order for the preview mode and Page Builder to work as expected, it is crucial that the query executor retrieves the page according to the context in which the query is executed:
- For the live site, retrieve the published versions of the page according to the validity of security claims upon page request.
- For preview and Page Builder, retrieve the page in the latest available version regardless of the workflow state and regardless whether it is secured or not.
You can achieve this by configuring the ContentQueryExecutionOptions
and providing them to the query executor.
In order to distinguish whether the query executor needs to retrieve the page for preview, you can make use of the IsPreview
property of IWebsiteChannelContext
described above.
// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;
private IWebsiteChannelContext websiteChannelContext;
// Information about whether to include secured items in the query execution passed from the caller
public async Task PageRetrieval(bool includeSecuredItems)
{
// Configures the query builder
var builder = new ContentItemQueryBuilder()...;
// Configures the query options for the query executor
var queryOptions = new ContentQueryExecutionOptions();
{
ForPreview = websiteChannelContext.IsPreview,
IncludeSecuredItems = includeSecuredItems || websiteChannelContext.IsPreview
};
// Executes the query and stores the data in generated 'ArticlePage' models
IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(
builder: builder,
options: queryOptions);
}
Add preview context to URLs
You may encounter problems in Preview mode on pages that send requests to a custom API endpoint, which uses IWebsiteChannelContext
to access the current channel in its implementation. To ensure that such endpoints work correctly in Preview mode, you need to add preview context data to the endpoint URL.
@using Kentico.Content.Web.Mvc
const endpointUrl = @Url.Kentico().ApplyPreviewContext("url");
The ApplyPreviewContext
Razor extension method adds various parameters to the endpoint URL, which ensure that IWebsiteChannelContext
is able to identify the channel, where the previewed page belongs, regardless of the domain used to access the admin UI.
Retrieve folders
To retrieve the folders from the content tree of a website channel (e.g., to create a page under the folder), use the Retrieve
method of the IWebPageFolderRetriever
interface (e.g., obtained via dependency injection).
// Services obtained via dependency injection
private readonly IWebPageFolderRetriever folderRetriever;
private IWebsiteChannelContext channelContext;
// Retrieves a folder from the specified path
WebPageFolder folder = (await folderRetriever.Retrieve(channelContext.WebsiteChannelName, PathMatch.Children("/Articles"))).FirstOrDefault();
// Use the WebPageFolder object to access information about the folder
int id = folder.ContentItemID;