Table of Contents

Coded Content-Type Definitions new v22

Tip

This section is a work in progress for Coded Data in 2sxc v22.

Background

Content Type Definitions contain the schema of an entity. They are objects which contain basic information such as

  1. a unique ID (Guid)
  2. a name
  3. all the field definitions

Internally every Content-Type-Definition are assembled using various Builders and Assemblers. The specs which lead to this assembly are loaded from various sources, including:

  1. The SQL database (the "normal" content-types)
  2. JSON files (for content-types which are usually loaded from the file system because they are global)
  3. Code-based definitions (for content-types which are used in code and should be strongly typed)
Tip

The cases "SQL" and "JSON" are documented elsewhere. Here we only focus on the code-based definitions.

Need for Code-Based Content-Type Definitions

There are many cases where we have both strictly typed C# data objects and entities, representing the same data. There are 2 typical scenarios:

  1. DB Data: Common data which comes from the DB (such as view definitions) which is used in code and services.
    This data already has a content-type definition generated, this is not the topic here.

  2. Service Data: Data which comes from a service, and is converted to entities (such as user information, site information, statistical information etc.)
    This is what we're looking at.

Service Data is prepared in POCO objects and converted to entities for further processing and forwarding to the UI (through REST/JSON) or to Razor (through services or DataSources).

Tip

Giving Service Data a clear type allows for later conversion of the entities to models.

Important

Not every raw data object needs a content-type definition.

We only need it on raw objects which are converted to entities and which are expected to be converted back to strongly typed objects later on.

This is because automatic ToModel conversion needs to know the exact name. Without a custom [ContentType] attribute, the name of the content-type will be derived from the class name, which may not be what you want.

Content-Type Definition - With or Without Attributes

It's important to know that every Raw to Entity conversion needs a content-type definition. So it will always be generated automatically.

The only question is whether you need full control of the definition, or whether you are happy with the automatic defaults.

Example

Here's an example of an object with attributes to specify the content-type definition:

/// <summary>
/// Content-Type for the general settings of a field (attribute) on a content-type.
/// </summary>
/// <remarks>
/// Note that as of 2026-07-26 there is no model yet to use, but it should be added soon.
/// </remarks>
[ModelSpecs(ContentType = Constants.ContentTypeName)]
[ContentType(
    Name = Constants.ContentTypeName,
    Guid = "0bab4be8-e795-4d9f-b50e-f7ec161ed8cb",  // If possible, should match the guid of the real database content-type, if it exists
    Description = "General settings for every Attribute (field) on a Content-Type."
)]
public interface IFieldSettingsGeneral : IModelFromEntity<FieldSettingsGeneralModel>
{
    [PrivateApi]
    public static class Constants { public const string ContentTypeName = "@All"; }

    [ContentTypeField(IsTitle = true)]
    string Name { get; }

    string DefaultValue { get; }

    /// <summary>
    /// Description of this field.
    /// </summary>
    string Notes { get; }

    /// <summary>
    /// The official input-type - usually something like `@string-default`
    /// </summary>
    string InputType { get; }

    //...
}

Controlled Content-Type Definition Specs

These specs are mainly needed for

  • serialization activities (such as IsTitle information)
  • detecting the type name/guid (like when converting back to models later on)

You can define custom specs on auto-generated Content Type Definitions using these attributes:

  1. [ContentType] - to set name / guid etc. on the class which defines the content-type

  2. [ContentTypeUse] - to reference another class which defines the content-type.

  3. [ContentTypeField] - to configure a field of the content-type, mainly for description etc.

  4. [ContentTypeTitle] - to configure a title-field of the content-type

  5. [ContentTypeIgnore] - to exclude object properties in the content-type definition

Internals

Auto-Generated Content-Type Definitions

Code defined types are automatically generated on-the-fly from C# classes, records and/or interfaces, usually at the time they are needed (during conversion of raw data to entities) and the resulting content-type is cached for future use.

Internally this is handled by two important components:

  1. The ContentTypesFromCodeBuilder - the system which builds a content-type definition from a C# class, record or interface
  2. The ContentTypesFromCodeManager - the system which manages and caches the content-type definitions

General Requirements and how it's Implemented

For this to work we want:

  1. To use the same C# POCOs to generate the content-type definition (to avoid separate definitions which can accidentally vary) - done by the ContentTypesFromCodeBuilder
  2. Automatically convert any POCO class/record to a content-type definition when needed - ContentTypesFromCodeBuilder
  3. Cache the generated content-type definitions to avoid repeated generation - ContentTypesFromCodeManager
  4. Reliably detect which type should be used based on the code itself, to use the same definition for each conversion, even on future requests - IDataFactory with ContentTypesFromCodeManager ...with option to manually set a different type, if needed (but should be rarely used)

Remarks about Anonymous Types

These will also be treated as if they were classes/records, without any decoration. The content-type will be generated based on the properties of the anonymous type. It will also cache the type, for future re-use, since these will usually be created again (anonymous types in C# are actually real types).

Maturity of the System as of 2026-07-24 (2dm)

  1. Descriptions work with
    1. No attributes at all (automatic defaults)
    2. With [ContentType] and [ContentTypeField] attributes
    3. Also on special properties such as Id, Guid, Created, Modified (added as special decorator ContentTypeBuiltInAttributesDecorator to the content-type)
  2. Ignore attribute works using [ContentTypeIgnore] attribute
  3. Builder can build from
    1. Anything with or without specs attributes
    2. classes (verified and has unit tests)
    3. records (verified and has unit tests)
    4. interfaces (verified and has unit tests)
    5. all of the above having a [ContentTypeUse] attribute to assign a different content-type (verified and has unit tests)
    6. anonymous - only without specs attributes (verified and has unit tests)
  4. Caching is working
  5. internal properties such as Id etc. are excluded in the content-type definition
  6. Test coverage for all these features and combinations
Tip

As of 2026-07-24 it appears that all cases are implemented and have unit tests covering them.