Skip to content

platform sdk custom fields

Andre Lafleur edited this page Oct 8, 2026 · 13 revisions

About custom fields

Custom fields are application-defined attributes attached to supported Security Center entities, such as cardholders, areas, and doors. Access custom field definitions and values through the ICustomFieldService exposed on the system configuration entity.

The examples on this page are partial and assume that engine is a connected Engine instance and that customFieldGuid, ownerGuid, and cardholder identify existing objects:

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

ICustomFieldService service = systemConfig.CustomFieldService;

Use ICustomFieldService with the target entity's Guid, or call GetCustomFields and SetCustomField on an Entity. The entity methods target that entity's own Guid, so both approaches provide the same read and write operations.

Look 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, entity type, 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 identifies the definition through Guid, Name, EntityType, ValueType, and Owner. It also exposes Mandatory, Unique, IsEncrypted, DefaultValue, GroupName, GroupPriority, and ShowInReports. You can set Name, GroupName, GroupPriority, IsEncrypted, and DefaultValue. The remaining properties are read-only after the field is built.

Custom field value types

The CustomFieldValueType enum selects the value type 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.

Create a custom field

Use service.CreateCustomFieldBuilder() and the fluent setters, and 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. For Text, Numeric, Boolean, DateTime, Decimal, and Date fields, also call SetDefaultValue with a value valid for the selected type before calling Build().
  • Name must be unique by the combination of EntityType, Owner, and CustomEntityTypeId. Build() rejects a definition whose combination already exists.
  • A unique custom field must also be mandatory. Build() rejects a definition marked unique without also being mandatory.
  • Mandatory is not supported on the Unit (access control unit), VideoUnit, LprUnit, or IntrusionUnit entity types. SetMandatory(true) is rejected for these types, as is Build() after such an attempt.
  • 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. Values with DateTimeKind.Local are converted to Coordinated Universal Time (UTC). Values with DateTimeKind.Unspecified are treated as UTC.

AddCustomFieldAsync and AddCustomFields throw an SdkException with SdkError.AlreadyExist for a duplicate definition and SdkError.InvalidEntityType for an unsupported entity type.

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.

Localize custom field labels

CustomField.Guid identifies the field definition. Name and GroupName are stored display text, and Security Center does not resolve them through a per-client resource key. Native Security Center pages display the same stored text after the client language changes.

Create one custom field for the data, not one field per language. Use its GUID in integration logic. A custom Workspace view can map that GUID to an integration resource key and resolve the label with Workspace.Culture. For this pattern, see Workspace SDK localization.

Read 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>, with one entry for every custom field defined for the entity's type; a field that has not been assigned a value is still included. Each CustomFieldValue exposes CustomField, Name, ValueType, and Value.

Write 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");

A custom field value change raises the target entity's CustomFieldsChanged event, not its FieldsChanged event. The event does not identify which custom field changed. For subscription and refresh guidance, see Detecting entity changes.

SetValue and SetValueAsync do not write an update when the new value equals the current value. Image-typed fields require the value to be a System.Drawing.Image instance.

To reset a field, call ClearValue:

service.ClearValue(field, cardholder.Guid);

ClearValue writes a type-specific empty value for most fields: an empty string for text, 0 for numeric and decimal, false for Boolean, and an empty GUID for image and entity fields. For Date and DateTime fields, and for text fields constrained to a custom data type, it writes the configured DefaultValue instead.

Remove custom field definitions

Remove a definition by its identifier:

service.RemoveCustomField(field.Guid);

await service.RemoveCustomFieldAsync(field.Guid);

Both overloads verify access to and local ownership of each definition. They throw an SdkException with SdkError.UnsufficientPrivilege when either check fails. A removal can throw KeyNotFoundException when no requested definition matches after validation.

See also

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Synergis RIO

Media Gateway

Genetec Web Player

Clone this wiki locally