Content item API
Xperience by Kentico provides the following API to manage and work with content items:
- Content item query – for content item retrieval
- Content item manager – for content item management
- Content item asset upload API – supporting API for content items with binary data
- Pages manager – for pages managements
Content item query
Content item query is the default system API for content item retrieval. It allows you to retrieve content items based on their content type. Each query can be modified using SQL-like fluent API.
Using content query consists of the following steps:
- Building the query using
ContentItemQueryBuilder
. - Running the query using
IContentQueryExecutor
and mapping the result to a model class for further use.
Build queries
To build content item queries, use ContentItemQueryBuilder
. The class provides fluent API that allows you to tailor each query to your requirements.
using CMS.ContentEngine;
// ...
// The builder class must be directly instantiated
var builder = new ContentItemQueryBuilder();
// Selects all items of the 'Acme.Article' content type
builder.ForContentType("Acme.Article");
Each ForContentType
call begins a subquery where you can further adjust the retrieval parameters for the corresponding content type.
// Selects an article called 'Security'
builder.ForContentType("Acme.Article", subqueryConfiguration =>
{
subqueryConfiguration
.TopN(1)
.Where(where => where.WhereEquals("ContentItemName", "Security"));
});
For all available parameterization options, see Reference - Content item query.
Finally, the entire query can be modified.
builder.ForContentTypes(parameters =>
{
parameters.OfContentType("Acme.Article", "Acme.NewsRelease")
})
// Sorts all records according to the 'ContentItemName' column
.Parameters(globalParams => globalParams.OrderBy("ContentItemName"));
The following diagram illustrates the general structure of content queries:
Loading other objects
To learn how to retrieve other types of data from the Xperience database, see ObjectQuery API.
Run queries and map the result
Queries are executed using IContentQueryExecutor
, which retrieves data according to the passed ContentItemQueryBuilder
instance. When retrieved, the query result is a collection of database rows. To transform the data into a typed format suitable for C#, part of query execution is a process known as model binding.
Model binding maps the data from each row to a C# object, assigning each column an appropriate C# type in the process. The resulting object instance is called a strongly-typed representation of the database data. Xperience provides code generators that enable developers to generate model classes (C# objects) directly mirroring each content type’s database representation. These classes are directly used in the model binding process.
IContentQueryExecutor
provides two approaches to facilitate model binding:
- GetMappedResult<TModel> (
GetMappedWebPageResult<TModel>
for page content types). These methods fully abstract the model binding process, directly returning strongly-typed models. - GetResult<TModel> (
GetWebPageResult<TModel>
for page content types). These methods expose the model binding logic that gives you direct access to each row of the database data, allowing you to customize the mapping process.
Using GetMappedResult methods
Using GetMappedResult<TModel>
, the system runs the query and binds the result to a collection of TModel classes automatically in the background. This approach is recommended for the majority of scenarios.
using CMS.ContentEngine;
// Contains an instance of 'IContentQueryExecutor'
// obtained using dependency injection
private readonly IContentQueryExecutor contentQueryExecutor;
var builder = new ContentItemQueryBuilder();
builder.ForContentType(Article.CONTENT_TYPE_NAME);
// The 'Article' class is generated by the code generator
// for a corresponding 'Article' content type
IEnumerable<Article> articles =
await contentQueryExecutor.GetMappedWebPageResult<Article>(builder);
The model binding logic matches database column names to the model’s properties, with certain exceptions made for system data.
When retrieving data that consists of multiple content types, you must, using the TModel generic, cast the result to a type shared by all model classes. Depending on the contents of the result, you have the following options:
Use
IContentItemFieldsSource
. This interface is by default implemented by all generated model classes.C#Getting items of multiple content typesusing CMS.ContentEngine; // Contains an instance of 'IContentQueryExecutor' // obtained using dependency injection private readonly IContentQueryExecutor contentQueryExecutor; var builder = new ContentItemQueryBuilder(); builder.ForContentTypes(query => { query.OfContentType(Article.CONTENT_TYPE_NAME, Blog.CONTENT_TYPE_NAME); query.WithContentTypeFields(); }); // Gets a mixed collection of articles and blogs IEnumerable<IContentItemFieldsSource> result = await executor.GetMappedResult<IContentItemFieldsSource>(builder); // Gets all articles List<Article> articles = result.OfType<Article>().ToList(); // Gets all blogs List<Blog> blogs = result.OfType<Blog>().ToList();
When retrieving items that share a reusable field schema, reference the schema interface in TModel:
C#Getting items that share a reusable field schemausing CMS.ContentEngine; // Contains an instance of 'IContentQueryExecutor' // obtained using dependency injection private readonly IContentQueryExecutor contentQueryExecutor; var builder = new ContentItemQueryBuilder(); builder.ForContentTypes(query => { query.OfReusableSchema("PageMetadata"); }); // Gets a collection if items with the 'PageMetadata' schema IEnumerable<IPageMetadata> result = await executor.GetMappedWebPageResult<IPageMetadata>(builder);
Use
System.Object
in case the data shares no common ancestor type.
The GetMappedResult
methods also provide overloads that allow you to manipulate the model after its data was bound.
IEnumerable<Article> articles =
await executor.GetMappedWebPageResult<Article>(builder, null, OverrideMapping);
// Called after each item is bound
// 'IContentQueryDataContainer' contains the current row data
// 'Article' is the instance of the bound model class
private Article OverrideMapping(IContentQueryDataContainer container, Article article)
{
// Custom logic to modify/extend the default mapping...
return article;
}
Using GetResult methods
Using GetResult<TModel>
allows you to take over the entire model binding process.
using CMS.ContentEngine;
// Contains an instance of 'IContentQueryExecutor'
// obtained using dependency injection
private readonly IContentQueryExecutor contentQueryExecutor;
// Executes the query specified within 'contentItemQueryBuilder'
// and binds it using the logic in the 'ModelBinder' delegate
var result =
await contentQueryExecutor.GetResult(contentItemQueryBuilder, ModelBinder);
Where ModelBinder
is a delegate function used to map the retrieved data to the result (can be asynchronous) that gives you direct access to each retrieved data row. You can use IContentQueryResultMapper.Map
, or provide custom binding logic to map the data.
using CMS.ContentEngine;
// Contains an instance of 'IContentQueryResultMapper' (e.g., obtained using dependency injection)
private readonly IContentQueryResultMapper mapper;
// Maps the result to 'MyModelClass'
private MyModelClass ModelBinder(IContentQueryDataContainer container)
{
// Maps the data from the container (representing
// one content item) to the model class
// The mapper performs case-insensitive mapping from the type's
// database columns to the class's properties, with a few exceptions
// (see the method's API documentation)
return mapper.Map<MyModelClass>(container);
}
Models can be either
- generated classes – generated classes directly mirror content type fields as defined via the field editor and work seamlessly with the mapper API.
- (advanced use case) custom classes – using custom classes enables you to map only desired columns. Before using custom classes, familiarize yourself with the mapper API or prepare custom mapping logic. Note that some Xperience APIs that work with content items expect certain system fields to be present in the model and will not work as expected otherwise.
using System;
using System.Collections.Generic;
using CMS.ContentEngine;
// Contains instances obtained using constructor dependency injection
private readonly IContentQueryExecutor contentQueryExecutor;
private readonly IContentQueryResultMapper mapper;
var contentItemQueryBuilder = new ContentItemQueryBuilder();
// Selects all objects of the 'VacationSpot' content type
contentItemQueryBuilder.ForContentType(VacationSpot.CONTENT_TYPE_NAME);
// Executes the query specified within 'contentItemQueryBuilder' and binds it to the 'VacationSpot' class generated for the 'VacationSpot' content type
IEnumerable<VacationSpot> result =
await contentQueryExecutor
.GetResult(contentItemQueryBuilder,
container => mapper.Map<VacationSpot>(container));
See the Content items section in the API Examples for more examples.
using System;
using System.Collections.Generic;
using CMS.ContentEngine;
// Contains instances obtained using constructor dependency injection
private readonly IContentQueryExecutor contentQueryExecutor;
private readonly IContentQueryResultMapper mapper;
// Executes the query specified within 'contentItemQueryBuilder' and binds it using the logic in 'DtoBinder'
IEnumerable<Dto> result = contentQueryExecutor.GetResult(contentItemQueryBuilder, DtoBinder);
// A function delegate that binds the returned records to a custom model.
// The content type of the item being bound is stored in 'IContentQueryDataContainer.ContentTypeName'
private Dto DtoBinder(IContentQueryDataContainer container)
{
// 'IContentQueryResultMapper' maps column data to corresponding
// properties based on matching names. For the example 'Dto' object,
// only columns named 'Title' and 'Content' get mapped in addition to 'SystemFields'.
// All other fields of the content type are ignored.
return mapper.Map<Dto>(container);
}
// A data transfer object used as a container for the retrieved data
// The structure of these objects is completely under your control
public class Dto
{
// Maps Xperience-specific fields
// When mapping pages, use the 'CMS.Websites.WebPageFields' type instead
public ContentItemFields SystemFields { get; set; }
// Maps the 'Title' column from the database
public string Title { get; set; }
// Maps the 'Content' column from the database
public string Content { get; set; }
}
Query execution options
The ContentQueryExecutionOptions
class allows you to optionally configure querying behavior. See Reference - Content item query for a list of available configuration options.
// Ensures the latest version of the selected content items,
// regardless of workflow state (e.g., returns items in 'Draft')
contentQueryExecutor.GetResult(contentItemQueryBuilder,
ModelBinder,
new ContentQueryExecutionOptions()
{ ForPreview = true });
Content item manager
Xperience provides a management API for content items via the IContentItemManager
class.
See the Content items section in the API Examples for examples of usage.
Pages manager
Xperience provides a management API for pages via the IWebPageManager
class.
See the Pages section in the API Examples for examples of usage.