Skip to content

platform sdk custom fields

Andre Lafleur edited this page May 10, 2026 · 13 revisions

About custom fields

In Security Center, custom fields are user-defined attributes attached to entities. They let an integration store domain-specific data on cardholders, areas, doors, or any other entity type without modifying the schema. The Platform SDK manages them through the ICustomFieldService exposed on the system configuration entity:

SystemConfiguration systemConfig = engine.GetEntity<SystemConfiguration>(
    SystemConfiguration.SystemConfigurationGuid);

ICustomFieldService service = systemConfig.CustomFieldService;

Common use cases:

  • Define new custom field types for cardholders, doors, or other entities (text, numeric, boolean, date, decimal, image, entity reference).
  • Attach domain-specific data to existing entities, such as a department on a cardholder or a contractor agency on a credential.
  • Read or update custom field values across many entities in bulk through the service.
  • Read or write a single entity's custom fields directly through Entity.GetCustomFields() and Entity.SetCustomField().

The same read and write operations are available through the service (passing the target entity's Guid) or through any Entity instance's GetCustomFields() and SetCustomField() methods. The entity-side methods delegate to the service with the entity's own Guid, so the two paths are interchangeable.

Looking up custom field definitions

Each custom field is described by a CustomField object. Enumerate every defined field through service.CustomFields, or fetch one by identifier, by name and entity type, or by name and owner:

IReadOnlyList<CustomField> all = service.CustomFields;

CustomField byId = service.GetCustomField(customFieldGuid);

CustomField byName = service.GetCustomField(
    "Department", EntityType.Cardholder);

CustomField byOwner = service.GetCustomField(
    "Department", EntityType.Cardholder, ownerGuid);

CustomField carries the field's Guid, Name, EntityType, ValueType, Mandatory, Unique, IsEncrypted, DefaultValue, GroupName, GroupPriority, and Owner. The display-related properties (Name, GroupName, GroupPriority, IsEncrypted, ShowInReports, DefaultValue) are writable; identity and typing properties are read-only after the field is built.

Custom field value types

The CustomFieldValueType enum selects the value shape used by a custom field:

Member Value Use for
Text 0 String values.
Numeric 1 Integer values.
Boolean 2 True or false.
DateTime 3 Date and time values.
Decimal 4 Decimal values.
Image 5 Image values; the boxed value must be a System.Drawing.Image.
Entity 6 A reference to another entity, stored as a Guid.
Date 7 Date-only values.

Creating a custom field

Use service.CreateCustomFieldBuilder() and the fluent setters, then call Build() to produce a CustomField. Persist the new definition with AddCustomFieldAsync(...) (or the synchronous AddCustomFields(...)):

CustomField field = service.CreateCustomFieldBuilder()
    .SetName("Department")
    .SetEntityType(EntityType.Cardholder)
    .SetValueType(CustomFieldValueType.Text)
    .SetDefaultValue("Unassigned")
    .Build();

await service.AddCustomFieldAsync(field);

Build() enforces these rules:

  • SetName, SetEntityType, and SetValueType are required. Build() throws InvalidOperationException if any of the three is missing.
  • Name must be unique by the combination of EntityType, Owner, and CustomEntityTypeId. A duplicate raises InvalidOperationException.
  • A unique custom field must also be mandatory. Calling SetUnique(true) without SetMandatory(true) raises InvalidOperationException.
  • Mandatory is not supported on AccessControlUnit, VideoUnit, LprUnit, or IntrusionUnit entity types. SetMandatory(true) on one of these (or Build() after such an attempt) raises an exception.
  • When EntityType is EntityType.CustomEntity, SetCustomEntityTypeId is required and must be a non-empty Guid. For every other entity type, SetCustomEntityTypeId must not be set.
  • GroupPriority must be greater than zero.
  • For DateTime value types, the default value must be a DateTime instance or a parseable date string. Local-kind values are converted to UTC; unspecified-kind values are treated as UTC.

AddCustomFieldAsync(field) and AddCustomFields(field) both raise SdkException(SdkError.AlreadyExist) if a field with the same Name/EntityType/Owner/CustomEntityTypeId combination already exists, and SdkException(SdkError.InvalidEntityType) if the entity type is not supported for custom fields.

To reuse a previously defined CustomFieldType (a constrained list of allowed values), pass it to the SetValueType(CustomFieldType) overload instead of the value-type enum.

Reading values

Read through the service or through the entity. Both return the boxed value, with generic <T> overloads for typed access:

object department = service.GetValue(field, cardholder.Guid);
string typed = service.GetValue<string>(field, cardholder.Guid);

string byName = service.GetValue<string>(
    "Department", cardholder.Guid);

IReadOnlyList<CustomFieldValue> values =
    await cardholder.GetCustomFieldsAsync();
CustomFieldValue companyValue = values.FirstOrDefault(
    v => v.Name == "Company");

GetCustomFields() and GetCustomFieldsAsync() return IReadOnlyList<CustomFieldValue>. Each CustomFieldValue exposes CustomField, Name, ValueType, and Value.

Writing values

Write through the service (synchronous or asynchronous) or through the entity:

service.SetValue(field, cardholder.Guid, "Engineering");

await service.SetValueAsync(field, cardholder.Guid, "Engineering");

cardholder.SetCustomField(field, "Engineering");
await cardholder.SetCustomFieldAsync("Department", "Engineering");

SetValue and SetValueAsync compare the new value against the current value and skip the write when they match. Image-typed fields require the value to be a System.Drawing.Image instance.

To reset a field to its configured default, call ClearValue:

service.ClearValue(field, cardholder.Guid);

ClearValue writes the field's DefaultValue, not null. It raises SdkException(SdkError.InvalidValue) if the field has no default value defined.

Removing custom field definitions

Remove a definition by its identifier:

service.RemoveCustomField(field.Guid);

await service.RemoveCustomFieldAsync(field.Guid);

Both overloads validate access and ownership and raise KeyNotFoundException if no matching definition is found.

For the Web SDK equivalent, see Web SDK custom fields.

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Synergis RIO

Media Gateway

Genetec Web Player

Clone this wiki locally