-
Notifications
You must be signed in to change notification settings - Fork 6
platform sdk entities
Entities are the fundamental building blocks in Security Center that represent all physical and logical objects. Every component in your system, from cameras and doors to users and access rules, is represented as an entity.
All entities in the SDK inherit from the abstract Entity base class, creating a unified object model:
// Entity is the abstract base class
public abstract class Entity
{
public Guid Guid { get; }
public int? LogicalId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime CreatedOn { get; }
public EntityType EntityType { get; }
// ... other common properties
}
// Specific entity types inherit from Entity
public class Camera : Entity { /* Camera-specific properties */ }
public class Cardholder : Entity { /* Cardholder-specific properties */ }
public class Door : Entity { /* Door-specific properties */ }
public class AccessRule : Entity { /* AccessRule-specific properties */ }Since all entities inherit from the base Entity class, you can work with them polymorphically:
// Generic entity handling
Entity someEntity = engine.GetEntity(entityGuid);
Console.WriteLine($"Entity: {someEntity.Name} (Type: {someEntity.EntityType})");
// Casting to specific types when you need type-specific properties
if (someEntity is Camera camera)
{
// Access camera-specific properties
Console.WriteLine($"Camera: {camera.Name} (Logical ID: {camera.LogicalId})");
}
else if (someEntity is Cardholder cardholder)
{
// Access cardholder-specific properties
Console.WriteLine($"Cardholder: {cardholder.FirstName} {cardholder.LastName}");
}
// Direct casting when you know the type
Camera camera = (Camera)engine.GetEntity(cameraGuid);
Camera camera = engine.GetEntity<Camera>(cameraGuid);
Cardholder cardholder = (Cardholder)engine.GetEntity(cardholderGuid);
Cardholder cardholder = engine.GetEntity<Cardholder>(cardholderGuid);All entities share common properties inherited from the base Entity class:
- Name: User-friendly display name (not unique - multiple entities can have the same name)
- Description: Optional detailed description
- GUID: Globally unique identifier (explained below)
- LogicalId: System-specific numeric identifier (explained below)
- CreatedOn: When the entity was created
- EntityType: Enumeration indicating the specific entity type
Unified Architecture: All entities share common properties and behaviors through inheritance, providing consistency across different types of objects.
Persistent Objects: Entities exist in the Directory Server database.
Real-time Updates: Changes to entities are automatically synchronized across all connected clients.
Hierarchical Organization: Entities can have parent-child relationships, enabling logical grouping.
The SDK supports numerous entity types, each serving specific purposes in your security system.
-
EntityType.Camera- Video surveillance devices -
EntityType.Door- Physical access points -
EntityType.Area- Geographic or logical zones -
EntityType.Zone- Security areas with specific rules -
EntityType.Cardholder- People with system access -
EntityType.Credential- Access cards, badges, or mobile credentials -
EntityType.AccessRule- Permissions defining who can access what -
EntityType.Schedule- Time-based access definitions -
EntityType.Partition- Logical groupings for organization -
EntityType.User- System users (administrators, operators) -
EntityType.UserGroup- Collections of users with similar roles -
EntityType.CustomEntity- Your custom entity types
Every entity in Security Center has two distinct identifiers that serve different purposes in system integration and management.
The GUID is a 128-bit unique identifier that guarantees uniqueness across all Security Center systems.
Key characteristics of GUIDs:
- Globally unique: No two entities will ever have the same GUID, even across different Security Center installations
- Persistent: The GUID never changes for the lifetime of the entity
- Cross-system safe: You can safely reference entities by GUID across different Security Center systems
- Database primary key: Used internally as the primary identifier in the Directory Server database
// Every entity has a GUID
Camera camera = engine.GetEntity<Camera>(cameraGuid);
Console.WriteLine($"Camera GUID: {camera.Guid}");
// GUIDs are unique across all Security Center systems
Guid cameraGuid = new Guid("12345678-1234-1234-1234-123456789ABC");
// This GUID will never exist on any other Security Center system
// Use GUID for reliable entity references
var myEntityReferences = new Dictionary<Guid, string>
{
{ camera.Guid, "Main entrance camera" },
{ cardholder.Guid, "John Doe employee record" }
};The Logical ID is a unique identifier that you can assign to entities to help reference them more easily. Logical IDs are local to your system and do not change the entity's default system-generated ID (GUID). You can use Logical IDs to quickly find entities.
Key characteristics of Logical IDs:
- System-specific: Only unique within a single Security Center system
- Type-specific: Camera Logical ID 100 is different from Door Logical ID 100
- Optional and manually assigned: Can only be set through the Config Tool or the SDK
- Nullable: May be null if not manually assigned
- Human-readable: Numeric values that are easier to work with than GUIDs
- Can be reused: When an entity is deleted, its Logical ID may be reused for new entities of the same type
// Logical ID is nullable and may be null if not manually assigned
Camera camera = engine.GetEntity<Camera>(cameraGuid);
Door door = engine.GetEntity<Door>(doorGuid);
Console.WriteLine($"Camera Logical ID: {camera.LogicalId?.ToString() ?? "Not assigned"}");
Console.WriteLine($"Door Logical ID: {door.LogicalId?.ToString() ?? "Not assigned"}");
// Logical IDs are type-specific within the same system
if (camera.LogicalId.HasValue)
{
Camera cameraByLogicalId = engine.GetEntity(EntityType.Camera, camera.LogicalId.Value);
}
// Use Logical ID for human-friendly references when available
if (camera.LogicalId.HasValue)
{
Console.WriteLine($"Processing Camera #{camera.LogicalId}: {camera.Name}");
}
else
{
Console.WriteLine($"Processing Camera: {camera.Name} (No Logical ID assigned)");
}
var accessRule = engine.GetEntity<AccessRule>(accessRuleGuid);
accessRule.Doors.Add(doorGuid); // Use GUID for relationships
// Logical ID for user display when available
if (door.LogicalId.HasValue)
{
Console.WriteLine($"Door #{door.LogicalId} - {door.Name}"); // User-friendly display
}To work with entities, you need to query them from the Directory Server using EntityConfigurationQuery and its specialized subtypes.
Note
For a complete guide to query types, pagination, cache behavior, and result limits, see About the ReportManager.
All EntityConfigurationQuery and its specialized subtypes return query results in a standard format:
- The query returns a
DataTablewith a single "Guid" column - Each row contains the GUID of an entity that matches your query filters
- You then use these GUIDs with
engine.GetEntity()to retrieve the actual entity objects
Important: All filters on queries are combined using AND logic, not OR logic.
When you set multiple filters on a query, entities must match all the specified criteria to be included in the results:
var cardholderQuery = (CardholderConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.CardholderConfiguration);
// These filters are combined with AND logic
cardholderQuery.FirstName = "John"; // AND
cardholderQuery.LastName = "Smith"; // AND
cardholderQuery.AccessStatus.Add(CardholderState.Active); // AND
cardholderQuery.VisitorsOnly = false; // AND
// Result: Only cardholders where ALL conditions are true:
// FirstName = "John" AND LastName = "Smith" AND Status = Active AND VisitorsOnly = falseExamples of AND behavior:
// This finds cameras that have BOTH conditions
var cameraQuery = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
cameraQuery.EntityTypeFilter.Add(EntityType.Camera);
cameraQuery.Name = "Lobby"; // Name contains "Lobby" AND
cameraQuery.Description = "Main"; // Description contains "Main"
// Result: Only cameras where name contains "Lobby" AND description contains "Main"
// This finds entities of multiple types (this IS an OR for entity types)
cameraQuery.EntityTypeFilter.Add(EntityType.Camera); // EntityType = Camera OR
cameraQuery.EntityTypeFilter.Add(EntityType.Door); // EntityType = Door
// Exception: EntityTypeFilter collection acts as OR - entities can be Camera OR DoorNote: The EntityTypeFilter collection is the exception - adding multiple entity types creates an OR condition for entity types, but all other filters remain AND conditions.
EntityConfigurationQuery: Can query any entity types but offers only basic filtering options.
Specialized Query Types: Can only query their specific entity type but provide advanced, type-specific filters.
-
CardholderConfigurationQuery- Only queries cardholders -
CredentialConfigurationQuery- Only queries credentials -
UserConfigurationQuery- Only queries users -
UserGroupConfigurationQuery- Only queries user groups -
AccessRuleConfigurationQuery- Only queries access rules
The EntityConfigurationQuery class is use for querying entities:
| Filter | Type | Description |
|---|---|---|
EntityTypeFilter |
EntityTypeCollection |
Entity types to include (OR logic between types) |
Name |
string |
Filter by entity name |
NameSearchMode |
StringSearchMode |
How to match the name (Contains, StartsWith, Is) |
Description |
string |
Filter by entity description |
DescriptionSearchMode |
StringSearchMode |
How to match the description |
EntityGuids |
Collection<Guid> |
Load specific entities by GUID |
CustomEntityTypes |
Collection<Guid> |
Filter custom entities by their type GUID |
LogicalId |
int? |
Filter by logical ID |
Owner |
Guid |
Filter by owner |
MaximumResultCount |
int |
Limit total number of results |
Page |
int |
Page number for pagination (starts at 1) |
PageSize |
int |
Number of results per page |
GuidsOnly |
bool |
Return only GUIDs without loading entity data |
DownloadAllRelatedData |
bool |
Download all related data for returned entities (may include non-matching entities in results) |
DownloadCustomFields |
bool |
Include custom field data |
StrictResults |
bool |
When true, results contain only entities matching the query criteria (use with DownloadAllRelatedData) |
async IAsyncEnumerable<Camera> QueryCameras()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.Page = 1; // First page is 1
query.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
// Query returns GUIDs, convert to actual Camera entities
var pageCameras = args.Data.AsEnumerable()
.Take(query.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<Camera>();
foreach (var camera in pageCameras)
{
yield return camera;
}
query.Page++; // Move to next page
} while (args.Data.Rows.Count > query.PageSize); // More pages if we got pageSize + 1 results
}// Always use pagination for multiple entity types - can return many entities
async IAsyncEnumerable<Entity> QueryMultipleTypes()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.EntityTypeFilter.Add(EntityType.Door);
query.EntityTypeFilter.Add(EntityType.Area);
query.Page = 1; // First page is 1
query.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
var pageEntities = args.Data.AsEnumerable()
.Take(query.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))));
foreach (var entity in pageEntities)
{
yield return entity;
}
query.Page++; // Move to next page
} while (args.Data.Rows.Count > query.PageSize); // More pages if we got pageSize + 1 results
}Use entity-specific query types that provide additional filters beyond the basic EntityConfigurationQuery:
Query for cardholder entities with filters for names, access status, visitor filtering, and time-based criteria.
Filters:
| Filter | Type | Description |
|---|---|---|
FirstName |
string |
Filter by first name |
FirstNameSearchMode |
StringSearchMode |
How to match first name |
FirstNameOrder |
OrderByType |
Sort order for first name |
LastName |
string |
Filter by last name |
LastNameSearchMode |
StringSearchMode |
How to match last name |
LastNameOrder |
OrderByType |
Sort order for last name |
FullName |
string |
Filter by full name |
FullNameSearchMode |
StringSearchMode |
How to match full name |
Email |
string |
Filter by email address |
EmailSearchMode |
StringSearchMode |
How to match email |
MobilePhoneNumber |
string |
Filter by mobile phone number |
MobilePhoneNumberSearchMode |
StringSearchMode |
How to match phone number |
AccessStatus |
Collection<CardholderState> |
Filter by access status (Active, Expired, Inactive) |
CardholderGroupIds |
Collection<Guid> |
Filter by cardholder group membership |
ActivationTimeRange |
TimeRange |
Filter by activation time range |
ExpirationTimeRange |
TimeRange |
Filter by expiration time range |
VisitorsOnly |
bool? |
Filter visitors only (true/false/null for both) |
EntitySharingCriteria |
EntitySharingCriteria |
Entity sharing filters |
async IAsyncEnumerable<Cardholder> FindCardholdersByName(string firstName)
{
var cardholderQuery = (CardholderConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.CardholderConfiguration);
// Cardholder-specific filters
cardholderQuery.FirstName = firstName;
cardholderQuery.FirstNameSearchMode = StringSearchMode.StartsWith;
cardholderQuery.AccessStatus.Add(CardholderState.Active);
cardholderQuery.VisitorsOnly = false; // Only regular cardholders
cardholderQuery.Page = 1; // First page is 1
cardholderQuery.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(cardholderQuery.BeginQuery, cardholderQuery.EndQuery, null);
var pageCardholders = args.Data.AsEnumerable()
.Take(cardholderQuery.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<Cardholder>();
foreach (var cardholder in pageCardholders)
{
yield return cardholder;
}
cardholderQuery.Page++; // Move to next page
} while (args.Data.Rows.Count > cardholderQuery.PageSize); // More pages if we got pageSize + 1 results
}Query for credential entities with filters for assignment status, mobile credentials, and format types.
Filters:
| Filter | Type | Description |
|---|---|---|
FormatType |
Collection<Guid> |
Filter by credential format type GUIDs |
UnassignedOnly |
bool |
Show only unassigned credentials |
MobileCredentialOnly |
bool? |
Filter mobile credentials only |
UniqueIds |
CredentialUniqueIdCollection |
Filter by specific credential unique IDs |
async IAsyncEnumerable<Credential> FindUnassignedCredentials()
{
var credentialQuery = (CredentialConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.CredentialConfiguration);
// Credential-specific options
credentialQuery.UnassignedOnly = true; // Only unassigned credentials
credentialQuery.MobileCredentialOnly = false;
credentialQuery.Page = 1; // First page is 1
credentialQuery.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(credentialQuery.BeginQuery, credentialQuery.EndQuery, null);
var pageCredentials = args.Data.AsEnumerable()
.Take(credentialQuery.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<Credential>();
foreach (var credential in pageCredentials)
{
yield return credential;
}
credentialQuery.Page++; // Move to next page
} while (args.Data.Rows.Count > credentialQuery.PageSize); // More pages if we got pageSize + 1 results
}Query for user entities with filters for names, email, status, and security levels.
Filters:
| Filter | Type | Description |
|---|---|---|
FirstName |
string |
Filter by first name |
FirstNameSearchMode |
StringSearchMode |
How to match first name |
FirstNameOrder |
OrderByType |
Sort order for first name |
LastName |
string |
Filter by last name |
LastNameSearchMode |
StringSearchMode |
How to match last name |
LastNameOrder |
OrderByType |
Sort order for last name |
Email |
string |
Filter by email address |
EmailSearchMode |
StringSearchMode |
How to match email |
Status |
Collection<UserStatus> |
Filter by user status (Activated, Deactivated) |
UserGroupIds |
Collection<Guid> |
Filter by user group membership |
SecurityLevelLowerBound |
int |
Lower bound for security level range |
SecurityLevelLowerBoundOperator |
FieldRangeType |
Operator for lower bound |
SecurityLevelUpperBound |
int |
Upper bound for security level range |
SecurityLevelUpperBoundOperator |
FieldRangeType |
Operator for upper bound |
GroupRecursive |
bool |
Include nested group memberships |
EntitySharingCriteria |
EntitySharingCriteria |
Entity sharing filters |
async IAsyncEnumerable<User> FindActiveUsers()
{
var userQuery = (UserConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.UserConfiguration);
// User-specific filters
userQuery.Status.Add(UserStatus.Activated);
userQuery.GroupRecursive = true; // Include nested groups
userQuery.Page = 1; // First page is 1
userQuery.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(userQuery.BeginQuery, userQuery.EndQuery, null);
var pageUsers = args.Data.AsEnumerable()
.Take(userQuery.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<User>();
foreach (var user in pageUsers)
yield return user;
userQuery.Page++; // Move to next page
} while (args.Data.Rows.Count > userQuery.PageSize); // More pages if we got pageSize + 1 results
}Query for user group entities with filters for email, status, and security levels.
Filters:
| Filter | Type | Description |
|---|---|---|
Email |
string |
Filter by email address |
EmailSearchMode |
StringSearchMode |
How to match email |
Status |
Collection<UserStatus> |
Filter by user status |
UserGroupIds |
Collection<Guid> |
Filter by user group membership |
SecurityLevelLowerBound |
int |
Lower bound for security level range |
SecurityLevelLowerBoundOperator |
FieldRangeType |
Operator for lower bound |
SecurityLevelUpperBound |
int |
Upper bound for security level range |
SecurityLevelUpperBoundOperator |
FieldRangeType |
Operator for upper bound |
GroupRecursive |
bool |
Include nested group memberships |
EntitySharingCriteria |
EntitySharingCriteria |
Entity sharing filters |
async IAsyncEnumerable<UserGroup> FindUserGroups()
{
var userGroupQuery = (UserGroupConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.UserGroupConfiguration);
// User group-specific filters
userGroupQuery.GroupRecursive = true;
userGroupQuery.Page = 1; // First page is 1
userGroupQuery.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(userGroupQuery.BeginQuery, userGroupQuery.EndQuery, null);
var pageUserGroups = args.Data.AsEnumerable()
.Take(userGroupQuery.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<UserGroup>();
foreach (var userGroup in pageUserGroups)
yield return userGroup;
userGroupQuery.Page++; // Move to next page
} while (args.Data.Rows.Count > userGroupQuery.PageSize); // More pages if we got pageSize + 1 results
}Query for access rule entities with filters for rule types.
Filters:
| Filter | Type | Description |
|---|---|---|
AccessRuleType |
AccessRuleType |
Filter by access rule type |
async IAsyncEnumerable<AccessRule> FindAccessRulesByType(AccessRuleType ruleType)
{
var accessRuleQuery = (AccessRuleConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.AccessRuleConfiguration);
// Access rule-specific filters
accessRuleQuery.AccessRuleType = ruleType;
accessRuleQuery.Page = 1; // First page is 1
accessRuleQuery.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(accessRuleQuery.BeginQuery, accessRuleQuery.EndQuery, null);
var pageAccessRules = args.Data.AsEnumerable()
.Take(accessRuleQuery.PageSize) // Exclude the +1 item used for pagination detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<AccessRule>();
foreach (var accessRule in pageAccessRules)
yield return accessRule;
accessRuleQuery.Page++; // Move to next page
} while (args.Data.Rows.Count > accessRuleQuery.PageSize); // More pages if we got pageSize + 1 results
}For large datasets, use pagination with IAsyncEnumerable<T> for memory-efficient processing:
When using pagination, Security Center returns pageSize + 1 results if more pages are available:
- The extra item (+1) is the first entity of the next page
- This helps detect if more pages exist without making additional queries
- Use
.Take(query.PageSize)to exclude this extra item from your results
// Streaming entities with IAsyncEnumerable for memory efficiency
async IAsyncEnumerable<Cardholder> QueryAllCardholders()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Cardholder);
query.Page = 1; // First page is 1
query.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
args = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
// Process entities from current page
var pageCardholders = args.Data.AsEnumerable()
.Take(query.PageSize) // Exclude the +1 item used for next page detection
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<Cardholder>();
// Yield each entity individually for streaming processing
foreach (var cardholder in pageCardholders)
yield return cardholder;
query.Page++; // Move to next page
} while (args.Data.Rows.Count > query.PageSize); // More pages if we got pageSize + 1 results
}
// Usage example:
async Task ProcessAllCardholders()
{
await foreach (var cardholder in QueryAllCardholders())
{
Console.WriteLine($"Processing: {cardholder.FirstName} {cardholder.LastName}");
// Process one cardholder at a time without loading all into memory
}
}async Task<Camera> FindCameraByName(string exactName)
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.Name = exactName;
query.NameSearchMode = StringSearchMode.Is;
query.MaximumResultCount = 1;
QueryCompletedEventArgs args = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
return args.Data.AsEnumerable()
.Select(row => engine.GetEntity(row.Field<Guid>(nameof(Guid))))
.OfType<Camera>()
.FirstOrDefault();
}Once you have entity GUIDs (from queries or other sources), you can retrieve the actual entity objects using the Engine's GetEntity methods.
// Get entity by GUID - returns base Entity type
Entity entity = engine.GetEntity(entityGuid);
// Get entity by GUID with query parameter - control server querying
Entity entity = engine.GetEntity(entityGuid, query: true);
// Get entity by GUID with generic type - returns specific type
Camera camera = engine.GetEntity<Camera>(cameraGuid);
Cardholder cardholder = engine.GetEntity<Cardholder>(cardholderGuid);
// Get entity by GUID with generic type and query parameter
Camera camera = engine.GetEntity<Camera>(cameraGuid, query: true);
// Get entity by EntityType and LogicalId
Camera entity = (Camera)engine.GetEntity(EntityType.Camera, logicalId);
Camera camera = engine.GetEntity<Camera>(EntityType.Camera, logicalId);The query parameter determines whether to query the server if the entity is not present in the local cache:
-
true: Query the server if the entity is not in cache (default behavior when parameter is omitted) -
false: Only return the entity if it's already in the local cache
// Basic retrieval
Camera camera = engine.GetEntity<Camera>(cameraGuid);
if (camera != null)
{
Console.WriteLine($"Camera: {camera.Name}");
}
// Using LogicalId (when available)
if (camera.LogicalId.HasValue)
{
// Retrieve same camera using LogicalId
Camera sameCamera = engine.GetEntity<Camera>(EntityType.Camera, camera.LogicalId.Value);
}The Engine provides several methods for creating different types of entities.
General entity creation method that works with any entity type:
// Create any entity type using EntityType enumeration
var cardholder = (Cardholder)engine.CreateEntity("John Doe", EntityType.Cardholder);
var camera = (Camera)engine.CreateEntity("Lobby Camera", EntityType.Camera);
var area = (Area)engine.CreateEntity("Building A", EntityType.Area);
// Create with parent relationship (applicable to Device, AccessPoint, and IntrusionArea)
var parentArea = engine.GetEntity<Area>(parentAreaGuid);
var childArea = (Area)engine.CreateEntity("Floor 1", EntityType.Area, parentArea.Guid);
// Create with parent and pre-specified GUID
var predefinedGuid = Guid.NewGuid();
var device = (Device)engine.CreateEntity("Custom Device", EntityType.Device, parentGuid, predefinedGuid);The CreateEntity method has three overloads:
-
CreateEntity(name, entityType): Creates an entity with an auto-generated GUID -
CreateEntity(name, entityType, parent): Creates an entity with a parent relationship -
CreateEntity(name, entityType, parent, entityGuid): Creates an entity with a pre-specified GUID
Note
The parent parameter is applicable to Device, AccessPoint, and IntrusionArea entity types. To place other entity types under an Area, create the entity first and then use the Area's Add methods.
Specialized method for creating access rules:
// Create different types of access rules
var accessRule = engine.CreateAccessRule("Standard Access", AccessRuleType.Permanent);
var temporaryRule = engine.CreateAccessRule("Temporary Access", AccessRuleType.Temporary);Method for creating custom entity instances:
// Create custom entity using custom entity type GUID
var customEntityTypeId = new Guid("12345678-1234-1234-1234-123456789ABC");
CustomEntity sensor = engine.CreateCustomEntity("Temperature Sensor 001", customEntityTypeId);
// Create custom entity with parent
var parentEntity = engine.GetEntity(parentEntityGuid);
CustomEntity childSensor = engine.CreateCustomEntity("Child Sensor", customEntityTypeId, parentEntity.Guid);Method for creating access points:
// Create access point with parent door
var parentDoor = engine.GetEntity<Door>(doorGuid);
var rex = engine.CreateAccessPoint("Request To Exist", AccessPointType.Rex, parentDoor.Guid);
var doorSensor = engine.CreateAccessPoint("Request Door Sensor", AccessPointType.DoorSensor, parentDoor.Guid);
var lockSensor = engine.CreateAccessPoint("Lock Sensor", AccessPointType.LockSensor, parentDoor.Guid);Method for creating devices:
// Create reader device
var parentUnit = engine.GetEntity<Unit>(unitGuid);
var readerDevice = engine.CreateDevice("Reader", DeviceType.Reader, parentUnit.Guid);
// Create input device
var inputDevice = engine.CreateDevice("Input", DeviceType.Input, parentUnit.Guid);
// Create output device
var outputDevice = engine.CreateDevice("Output", DeviceType.Output, parentUnit.Guid);Entity properties can be modified directly. Changes are automatically sent to the Directory Server as the entity is modified.
// Get and modify a cardholder
var cardholder = engine.GetEntity<Cardholder>(cardholderGuid);
cardholder.FirstName = "John";
cardholder.LastName = "Smith";
cardholder.EmailAddress = "john.smith@company.com";
cardholder.MobilePhoneNumber = "+1-555-0123";// Modify a camera
var camera = engine.GetEntity<Camera>(cameraGuid);
camera.Name = "Updated New Camera Name";
camera.Description = "Updated camera description";// User properties
var user = engine.GetEntity<User>(userGuid);
user.FirstName = "Admin";
user.LastName = "User";
user.EmailAddress = "admin@company.com";// Area properties
var area = engine.GetEntity<Area>(areaGuid);
area.Name = "Building A";
area.Description = "Main office building";Entities can be deleted using the DeleteEntity method on the Engine.
// Delete by GUID
engine.DeleteEntity(entityGuid);
// Delete using entity reference
Entity entity = engine.GetEntity(entityGuid);
engine.DeleteEntity(entity);-
Security Center SDK Developer Guide Overview of the SDK framework and how to build integrations with Security Center.
-
Platform SDK
- Overview Introduction to the Platform SDK and core concepts.
- Connecting to Security Center Step-by-step guide for connecting and authenticating with the SDK.
- SDK Certificates Details certificates, licensing, and connection validation.
- Referencing SDK Assemblies Best practices for referencing assemblies and resolving them at runtime.
- SDK Compatibility Guide Understanding backward compatibility and versioning in the SDK.
- Entity Guide Explains the core entity model, inheritance, and how to work with entities.
- Entity Cache Guide Describes the engine's local entity cache and synchronization.
- Transactions Covers batching operations for performance and consistency.
- Events Subscribing to real-time system events.
- Actions Sending actions to Security Center.
- Security Desk Displaying content on monitors, reading tiles, sending tasks, and messaging operators.
- Custom Events Defining, raising, and subscribing to custom events.
- ReportManager Querying entities and activity data from Security Center.
- ReportManager Query Reference Complete reference of query types, parameters, and response formats.
- Privileges Checking, querying, and setting user privileges.
- Partitions Entity organization and access control through partitions.
- Logging How to configure logging, diagnostics, and debug methods.
-
Plugin SDK
- Overview Introduction to plugin architecture and capabilities.
- Certificates SDK certificate requirements for plugin roles.
- Lifecycle Initialization and disposal patterns.
- Threading Threading model, QueueUpdate, and async patterns.
- State Management Reporting plugin health and diagnostics.
- Configuration Configuration storage and monitoring.
- Restricted Configuration Secure credential storage and admin-only configuration.
- Events Event subscription and handling.
- Queries Query processing and response handling.
- Request Manager Request/response communication with clients.
- Database Database integration and schema management.
- Entity Ownership Understanding plugin-owned entities, running state management, and ownership release.
- Entity Mappings Using EntityMappings for plugin-specific configuration and external system integration.
- Server Management High availability and server failover.
- Custom Privileges Defining and enforcing custom privileges.
- Custom Entity Types Defining and managing plugin-specific entity types.
- Resolving Non-SDK Assemblies Handling third-party dependencies in plugins and workspace modules.
- Deploying Plugins Registering and deploying plugins and workspace modules.
- .NET 8 Support Building plugins with .NET 8 and .NET Standard compatibility.
-
Workspace SDK
- Overview Introduction to client-side UI extensions for Security Desk and Config Tool.
- Certificates SDK certificate requirements for workspace modules.
- Creating Modules Module lifecycle, registration patterns, and assembly resolution.
- Tasks Executable actions, home page entries, and programmatic invocation.
- Pages Page content, lifecycle, descriptors, and navigation.
- Components Dashboard widgets, tiles, maps, credentials, and content builders.
- Tile Extensions Custom tile widgets, views, and properties panels.
- Services Built-in services for dialogs, maps, alarms, badges, and more.
- Contextual Actions Right-click context menu extensions.
- Options Extensions Custom settings pages in application preferences.
- Configuration Pages Entity configuration pages for Config Tool.
- Monitors Multi-monitor support and shared components.
- Shared Components Using monitor and workspace shared UI components.
- Commands Command execution, evaluation, and interception.
- Extending Events Adding custom fields to Security Center events.
- Map Extensions Custom map objects, layers, and providers.
- Timeline Providers Custom timeline event sources for video playback.
- Image Extractors Custom image sources for cardholder photos and custom fields.
- Credential Encoders Encoding credentials with custom encoder components.
- Cardholder Fields Extractors Importing cardholder data from external sources.
- Content Builders Building and customizing tile content in Security Desk.
-
Macro SDK
- Overview How macros work, creating and configuring macro entities, automation, and monitoring.
- Developer Guide Developing macro code with the UserMacro class and Security Center SDK.
-
- Getting Started Setup, authentication, and basic configuration for the Web SDK.
- Referencing Entities Entity discovery, search capabilities, and parameter formats.
- Entity Operations CRUD operations, multi-value fields, and method execution.
- About access control in the Web SDK Concepts, relationships, and common access-control operations.
- About video in the Web SDK Concepts, relationships, configuration, and common video operations.
- Users and user groups Creating users, managing group membership, and assigning privileges.
- Partitions Managing partitions, entity membership, and user access control.
- Custom Fields Creating, reading, writing, and filtering custom entity fields.
- Custom Card Formats Managing custom credential card format definitions.
- Actions Control operations for doors, cameras, macros, and notifications.
- Events and Alarms Real-time event monitoring, alarm monitoring, and custom events.
- Incidents Incident management, creation, and attachment handling.
- Reports Activity reports, entity queries, and historical data retrieval.
- Tasks Listing and executing saved report tasks.
- Macros Monitoring currently running macros.
- Custom Entity Types Listing, retrieving, and deleting custom entity type descriptors.
- System Endpoints License usage, web tokens, and exception handling.
- Performance Guide Optimization tips and best practices for efficient API usage.
- Reference Entity GUIDs, EntityType enumeration, and EventType enumeration.
- Under the Hood Technical architecture, query reflection, and SDK internals.
- Troubleshooting Common error resolution and debugging techniques.
- Media Gateway Guide Setup and configuration of the Media Gateway role for video streaming.
- Developer Guide Complete guide to integrating GWP for live and playback video streaming.
- API Reference Full API documentation with interfaces, methods, properties, and events.
- Sample Application Comprehensive demo showcasing all GWP features with timeline and PTZ controls.
- Multiplexing Sample Multi-camera grid demo using a shared WebSocket connection.