Generate code files for system objects

Certain types of objects in the system can contain custom fields that are used to model and structure the content stored within them. A typical example is a content type object with a title, article summary, and article text. Custom fields are assigned either via the field editor or the Form Builder editing interface and correspond to a single database column.

Since each object can contain a different set of custom fields, it’s impossible to provide strongly-typed access to individual fields via a shared general class. For this reason, accessing custom fields can be unwieldy, often needing additional code to be written. The process requires developers to:

  • specify database column names to manipulate data from particular fields, and
  • manually perform value type conversion and validation on the data as it gets retrieved from and stored to the database.

Therefore, to make working with such objects easier, the system allows you to generate object-specific code files. A code file contains properties that correspond to custom fields defined for the source object (e.g., title, article summary, article text for a content type). Each such property is assigned a data type and getter/setter logic suitable for manipulating the data of the underlying field. This allows you to work with the field’s data using the underlying C# data type without writing additional code. For more information about field data types, see Field data type management.

Code generation is available for the following objects:

  • Reusable content types – generates a class with the reusable content type’s fields as properties. See Content item API to learn about available API that can be used with generated content type classes.
  • Page content types – generates a class with the page content type’s fields as properties. See Content item API to learn about available API that can be used with generated page classes.
  • Reusable field schemas – generates an interface that defines the corresponding schema’s fields as its properties.
  • Forms – generates a class with the form’s fields as properties. See Content retrieval to learn about available API that can be used with generated form classes.
  • Object types – generates classes that facilitate working with object types. See Database table API to learn about the architecture and available API of such objects.

Generate code files

The code generator is command line-based. Code files are generated via the dotnet run --kxp-codegen .NET CLI command. You can run the generator from a command line interface of your choice (cmd, PowerShell, Bash).

Run the command from the root directory of your Xperience project:



cd my/Xperience/app/root
dotnet run --no-build -- --kxp-codegen --type "ReusableContentTypes"

Command parameters

Add the --no-build parameter to the dotnet run command if you don’t wish to rebuild the project before the classes are generated.

Add the -- syntax separator before any command parameters that you wish to pass directly to the Xperience application (--kxp-codegen). This prevents conflicts with general .NET CLI parameters, for example when using the --help option.

The code generator supports the following parameters. You can also view the supported parameters by running the generator with the --help option:

Parameter 

Required

Description

--type

Yes

Sets the type of objects for which the code files are generated. Available types: 

  • Forms – generates code files for forms.
  • ReusableContentTypes – generates code files for reusable content.
  • PageContentTypes – generates code files for pages.
  • ReusableFieldSchemas – generates code files for reusable field schemas.
    • You must set the --namespace parameter when using this option.
    • Use together with the ReusableContentTypes orPageContentTypes option which generate classes that already implement all assigned reusable schema interfaces.
    • Make sure to generate schema interfaces into the same namespace as your content type classes. The generator outputs uncompilable code otherwise.
    • For more information, see Reusable field schema interfaces.
  • Classes – generates code files for object types. Code generation for object types can be further configured in the administration, see Configure code generation for data classes.
    • Use together with the --with-provider-class parameter to generate the corresponding *Provider class and interface.

The switches are case-sensitive.

Example

cd my/Xperience/app/root
dotnet run -- --kxp-codegen --type "ReusableContentTypes"

--skip-confirmation

No

Skips the confirmation message displayed before the code files are generated.

--include

No

Pattern to limit the included objects. Use ‘;’ to separate multiple object names. Use the ‘*’ wildcard character to match all objects with the same prefix. Reusable field schemas don’t use a namespace prefix, but you can use a shared code name prefix to allow bulk include. 

For example:


dotnet run -- --kxp-codegen --type "ReusableContentTypes" --include "MyProject.Article;Acme.*"

--exclude

No

Pattern to define the excluded objects. Use ‘;’ to separate multiple object names. Use the ‘*’ wildcard character to match all objects with the same prefix.  Reusable field schemas don’t use a namespace prefix, but you can use a shared code name prefix to allow bulk exclude.

For example:


dotnet run -- --kxp-codegen --type "ReusableContentTypes" --exclude "MyProject.Article;Acme.*"

--location

No

The absolute or relative path of the target folder where the code files are generated. Path values support the following macros: 

  • {type} – replaced by a string representing the object type (e.g. ReusableContentTypes).
  • {dataClassNamespace} – replaced by the namespace from the object name (e.g. Acme for Acme.Article). Resolves to an empty string when generating ReusableFieldSchemas.
  • {name} – replaced by the object name without the namespace.

If the location is not provided, the code file target is the /{type}/{dataClassNamespace}/{name}/ folder hierarchy in the application directory.

--namespace

No

The custom namespace added to the code of the generated classes. If not provided, a default system namespace is used based on the generated object type. The default values for the namespace of each type are the following:

  • Formsnamespace CMS.OnlineForms.Types
  • ReusableContentTypesnamespace {contentTypeName}
  • PageContentTypesnamespace {contentTypeName}
  • ReusableFieldSchemas – no default namespace. Must be specified using the --namespace parameter.
  • Classesnamespace {objectTypeName}

When setting a custom namespace, you can use the following macros in the parameter value:

  • {type} – replaced by a string representing the object type (e.g. ReusableContentTypes).
  • {dataClassNamespace} – replaced by the namespace from the object name (e.g. Acme for Acme.Article). Resolves to an empty string when generating ReusableFieldSchemas.
  • {name} – replaced by the object name without the namespace.

--with-provider-class

No

Supported values:
True/False

Applies only when generating object type classes (--type Classes). Controls whether a corresponding provider class *Provider and interface I*Provider is generated for the selected object types.

Defaults to True for backward compatibility with existing projects – calling the code generator without this parameter specified always generates provider classes and interfaces for all selected object types. You must explicitly call --with-provider-class False to disable this behavior.

We don’t recommend generating dedicated provider classes per object type and instead using the generic IInfoProvider<TInfo> for management operations. See Database table API for more information. Going forward, all provider APIs will migrate to this generic approach.

Example

# Generates only *Info classes
dotnet run -- --kxp-codegen --type "Classes" --with-provider-class False

The system generates the code files in the specified location and folder structure.

Discovery of generated classes in custom assemblies

When using the generated code files in a separate library or external application, you need to allow the system to detect the classes. Make sure class discovery is enabled for the project – see Integrate custom code.

Note: Don’t directly add generated code files into external projects that compile into a different output type than a DLL assembly (for example console applications). The system cannot discover the code in these cases. Instead, add the code into a Class Library project with the AssemblyDiscoverable attribute and reference the assembly from your project.

Reusable field schema interfaces

Code files generated via ReusableContentTypes or PageContentTypes for content types that use at least one reusable field schema implement I<SchemaName>Fields interfaces. Each such interface corresponds to a schema assigned to the given content type. You must generate these interfaces separately using the ReusableFieldSchemas --type parameter. Make sure to place them under the same namespace as the content type classes that use them. The generator outputs uncompilable code otherwise.

For example, assume an Article page content type that uses the PageMetada and SEO reusable field schemas.

To generate the page content type, run:

Generate page content types


dotnet run -- --kxp-codegen --type "PageContentTypes" --namespace "My.Project"

Which outputs:

Example generated class and its contents


namespace My.Project
{
    public partial class Article : IPageMetadata, ISEO, IWebPageFieldsSource
    {
        // Properties that represent the 'PageMetadata' and 'SEO' reusable schema fields

        // The SystemFields property

        // Properties that represent 'Article' content type fields
    }
}

To generate the corresponding reusable schema interfaces, run:



dotnet run -- --kxp-codegen --type "ReusableFieldSchemas" --namespace "My.Project"

Which outputs:

IPageMetada reusable schema interface


namespace My.Project
{
    public interface IPageMetadata
    {
        public const string REUSABLE_FIELD_SCHEMA_NAME = "PageMetadata";

        // Properties that represent 'PageMetadata' reusable schema fields
    }
}

ISEO reusable schema interface


namespace My.Project
{
    public interface ISEO
    {
        public const string REUSABLE_FIELD_SCHEMA_NAME = "SEO";

        // Properties that represent 'SEO' reusable schema fields
    }
}

Model mapping preferences

When mapping the results of database queries to generated model classes, the system by default uses the type of the generated interface when saturating properties that represent reusable field schemas. You can override this behavior and specify which model class a given content type referenced under a reusable field schema maps to using the MapContentTypeReferenceTo and MapReferenceTo attributes.

Specify model classes for automatic mapping

// Maps content types of type 'Blog.BLOG_CLASS_NAME' from the collection of items
// referenced by the 'IPageMetadata' schema to the 'Blog' model class.
[MapContentTypeReferenceTo(Blog.BLOG_CLASS_NAME, typeof(Blog))]

// Maps content types of type 'Article.ARTICLE_CLASS_NAME' from the collection of items
// referenced by the 'IPageMetadata' schema to the 'Article' model class.
[MapContentTypeReferenceTo(Article.ARTICLE_CLASS_NAME, typeof(Article))]

// All other content types map to the 'PageMetadata' model class
[MapReferenceTo(typeof(PageMetadata))]

// Property representing reusable field schema references
public IEnumerable<IPageMetadata> Pages { get; set; }

// A custom implementation of the 'IPageMetadata' interface containing 
// a subset of the schema's properties 
public class PageMetadata : IPageMetadata
{
    public string Title { get; set; }
}

When no mapping preferences are specified, the system defaults first to the type of the property representing the reusable schema (IPageMetadata in the example above) and finally to the type registered via RegisterContentTypeMappingAttribute.

IContentItemFieldsSource and IWebPageFieldsSource interfaces

Classes generated for reusable content types and web pages respectively implement the IContentItemFieldsSource and IWebPageFieldsSource interfaces. These interfaces are useful when accessing system properties across multiple content types, or when defining extension methods across all generated classes.

Example - access system fields across multiple content types


// Instances of services obtained via dependency injection
private readonly IContentQueryExecutor contentQueryExecutor;
private readonly IContentQueryResultMapper contentQueryResultMapper;

public async Task<IEnumerable<IContentItemFieldsSource>> FetchMultipleContentTypes()
{
    // Gets multiple content types in a single query
    var builder = new ContentItemQueryBuilder()
                            .ForContentTypes(query => 
                            {
                                query.OfContentType(Coffee.CONTENT_TYPE_NAME, Event.CONTENT_TYPE_NAME)
                            });

    // Uses 'IContentItemFieldsSource' as the common type
    return await contentQueryExecutor.GetMappedResult<IContentItemFieldsSource>(builder);
}

Example - extension method on IWebPageFieldsSource


public static class WebPageFieldsSourceExtensionMethods
{
    public static object GetSystemProperties(this IWebPageFieldsSource source)
    {
        return new { Guid = source.SystemFields.ContentItemGUID, 
                     Id   = source.SystemFields.ContentItemID };
    }
}

Customize generated classes

In most scenarios, we do not recommend directly modifying the generated classes.

The classes as generated as partial classes. This means that you can extend them in a separate code file. Using this approach, you avoid the need to merge custom changes made to the generated code every time the class is generated again after the object’s properties are changed.

Example

ArticlePage.generated.cs - generated class


namespace DancingGoat
{
    // Partial class generated by the code generator for content type 'DancingGoat.Store'
    public partial class Store : IWebPageFieldsSource
    {
        ...

        /// <summary>
        /// Store name.
        /// </summary>
        public string StoreName { get; set; }

         /// <summary>
        /// Store location.
        /// </summary>
        public string StoreLocation { get; set; }

        ...
    }
}

ArticlePage.cs - extending the generated class


namespace DancingGoat
{
    // Partial class extending the generated 'Store' class
    public partial class Store
    {
        public string StoreFullName { get => $"{StoreName}-{StoreLocation}" }
    }
}

Configure code generation for data classes

You can further configure code generation for object types under Modulesselect a moduleClassesedit a classCode.

Setting

Description

Object type

The identifier of the object type in the system. Must be unique within the Xperience instance. We recommend prefixing object types with a shared identifier. For example, system object types begin with the CMS. prefix (this prefix is reserved). 

Display name column

Stores a human-readable name of the object. Reflected in UIs that work with objects (e.g., in breadcrumbs, navigation, object listings). Depends mainly on the type of the used UI page.

Code name column

Stores the code name of each object. This column is used to identify the object when retrieving objects via their code name.

If set, generated provider interfaces by default contain a Get(string codename) method.

GUID column

Stores the GUID of each object. This column is used to identify the object when retrieving objects via GUIDs. If set, generated provider interfaces by default contain a Get(Guid guid) method.

Only columns with the GUID data type can be selected.

“Last modified” column

If set, can be automatically populated by the system when performing certain supported actions with objects of the given type, such as updates (calling Set on the corresponding provider).

Only columns with the DateTime data type can be selected.

Binary column

Stores associated binary data.

Only columns with the Binary data type can be selected.

Additionally, columns that can be used to uniquely identify individual records in the database (ID, Code name, GUID) have the Use hashtable option available. If the option is enabled, retrieved objects are cached under the corresponding identifier. For subsequent queries targeting previously retrieved records, the cached values are used, reducing database usage. However, note that enabling hashtable caching for data classes with a significant number of records that are often loaded by the system may result in a large increase in application memory usage. See Object type configuration.