-
Notifications
You must be signed in to change notification settings - Fork 4
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 IP: {camera.IpAddress}");
}
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.
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 |
List<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 |
List<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 |
List<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 |
List<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
- Platform SDK Overview Introduction to the Platform SDK and core concepts.
- SDK Certificates Details certificates, licensing, and connection validation.
- 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.
- SDK Transactions Covers batching operations for performance and consistency.
- ReportManager Querying entities and activity data from Security Center.
- Events and Actions Subscribing to events and handling actions.
- Logging with the Genetec SDK How to configure logging, diagnostics, and debug methods.
- Referencing SDK Assemblies Best practices for referencing assemblies and resolving them at runtime.
- SDK Compatibility Guide Understanding backward compatibility and versioning in the SDK.
-
Plugin SDK
- Plugin SDK Overview Introduction to plugin architecture and capabilities.
- Plugin SDK Certificates SDK certificate requirements for plugin roles.
- Plugin SDK Lifecycle Initialization and disposal patterns.
- Plugin SDK Threading Threading model, QueueUpdate, and async patterns.
- Plugin SDK Configuration Configuration storage and monitoring.
- Plugin SDK Restricted Configuration Secure credential storage and admin-only configuration.
- Plugin SDK Database Database integration and schema management.
- Plugin SDK Events Event subscription and handling.
- Plugin SDK Queries Query processing and response handling.
- Plugin SDK Request Manager Request/response communication with clients.
- Plugin SDK Entity Ownership Understanding plugin-owned entities, running state management, and ownership release.
- Plugin SDK Entity Mappings Using EntityMappings for plugin-specific configuration and external system integration.
- Plugin SDK State Management Reporting plugin health and diagnostics.
- Plugin SDK Server Management High availability and server failover.
- Custom Privileges Defining and enforcing custom privileges.
- Resolving Non-SDK Assemblies Handling third-party dependencies in plugins and workspace modules.
- Deploying Plugins Registering and deploying plugins and workspace modules.
-
- Macro SDK Developer Guide Complete guide to creating server-side automation scripts in Security Center using C#.
- 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.
- 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.
- 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.
- Web Player Guide Complete guide to integrating GWP for live and playback video streaming.
- Web Player API Reference Full API documentation with interfaces, methods, properties, and events.
- Web Player Sample Application Comprehensive demo showcasing all GWP features with timeline and PTZ controls.
- Genetec Web Player Multiplexing Sample Multi-camera grid demo using a shared WebSocket connection.