-
Notifications
You must be signed in to change notification settings - Fork 4
platform sdk entity cache
The Engine's entity cache is a fundamental component of the Genetec SDK that provides efficient, client-side storage and management of entities retrieved from the Security Center system. Think of it as a local copy of the entities your application needs, which stays automatically synchronized with the server.
Before diving into how the cache works, it's important to understand what entities are in the Genetec SDK context.
An Entity is the base abstract class that represents any object in your Security Center system. All entities in Security Center inherit from this base Entity class, which provides common properties and functionality shared across all entity types.
Every entity has two types of identifiers:
GUID (Global Unique Identifier):
- Always present and immutable
- 36-character format:
5645151a-d758-429c-8b09-25c125b6a6fb - Unique across the entire system
- Automatically assigned when the entity is created
Logical ID (optional):
- Integer value from 0 to 9,999,999 (7 digits maximum)
- Must be manually assigned through Config Tool or the SDK
- Can be changed after creation
- Not unique across entity types (a Camera and a Door can both have logical ID 123)
- Useful for human-readable identification
-
GetEntity(EntityType, logicalId)throwsArgumentOutOfRangeExceptionif outside valid range
The SDK includes many specific entity types that inherit from the base Entity class:
// Base class with common properties
Entity entity = engine.GetEntity(someGuid);
string name = entity.Name; // Common property
string description = entity.Description; // Common property
// Specific entity types with additional properties
Camera camera = engine.GetEntity<Camera>(cameraGuid);
// Camera-specific properties would be available here
Cardholder cardholder = engine.GetEntity<Cardholder>(cardholderGuid);
string firstName = cardholder.FirstName; // Cardholder-specific property
string lastName = cardholder.LastName; // Cardholder-specific propertyCommon entity types include:
- Camera, Door, Area, AccessPoint
- Cardholder, CardholderGroup, Credential
- Alarm, Schedule, AccessRule
- Role, User, UserGroup
- And many others
Entities can be related to each other, forming a hierarchy or network of connections. For example:
- A Camera belongs to a VideoUnit (physical device)
- A Door can have multiple AccessPoints (card readers)
- A Cardholder can belong to multiple CardholderGroups
Understanding these relationships is important when working with DownloadAllRelatedData, which we'll cover later.
- Performance: Fast local access to entity data without repeated server queries
- Real-time Updates: Automatic synchronization with server-side changes
- Reduced Network Traffic: Minimizes communication with the server
- Consistency: Ensures your application has up-to-date entity information
The entity cache is thread-safe for read operations. You can safely call GetEntity() and GetEntities() from any thread.
Note
While cache access is thread-safe, GetEntity(guid) with default behavior may trigger a server query if the entity is not cached. This I/O operation can block the calling thread. Use GetEntity(guid, query: false) when you need guaranteed non-blocking cache-only access.
The cache maintains exactly one object instance per entity using a dictionary structure for fast lookups. This means:
// These both return the SAME object instance
Entity entity1 = engine.GetEntity(someGuid);
Entity entity2 = engine.GetEntity(someGuid);
// entity1 and entity2 point to the exact same object in memory
Console.WriteLine(ReferenceEquals(entity1, entity2)); // True, same reference!Each Engine instance maintains its own separate cache:
using var engine1 = new Engine();
using var engine2 = new Engine();
// Both connect to the same Directory Server
await engine1.LogOnAsync(server, username, password);
await engine2.LogOnAsync(server, username, password);
// Both load the same camera
await LoadCameras(engine1);
await LoadCameras(engine2);
Entity camera1 = engine1.GetEntity(someCameraGuid);
Entity camera2 = engine2.GetEntity(someCameraGuid);
// These are DIFFERENT object instances
Console.WriteLine(ReferenceEquals(camera1, camera2)); // False, different references!
// But they represent the same logical entity
Console.WriteLine(camera1.Guid == camera2.Guid); // True, same entity GUIDWhen the Engine loses connection to the server:
- The cache is cleared - all entity objects are disposed and removed
-
GetEntity()will returnnullfor previously cached entities - Existing entity references continue to exist but point to disposed objects
- These disposed entity objects have
IsDisposed = true - Accessing properties on disposed entities returns default values (empty string,
Guid.Empty, 0, etc.) - Upon reconnection, you must reload entities to repopulate the cache
- Existing references still point to the old disposed objects, not new fresh ones
Important: You cannot dispose entity objects yourself. The Dispose() method is internal to the SDK. Only the Engine manages entity lifecycle.
Entity camera = engine.GetEntity(someCameraGuid);
Console.WriteLine(camera.IsDisposed); // False - entity is active
Console.WriteLine(camera.Name); // "Camera 01" - actual name
// Connection is lost...
Console.WriteLine(camera.IsDisposed); // True - entity is disposed
Console.WriteLine(camera.Name); // "" - empty string (default value)
Console.WriteLine(camera.Guid); // Guid.Empty (default value)
// Always check IsDisposed before using entity data
if (!camera.IsDisposed)
{
Console.WriteLine(camera.Name);
}
// After reconnection and reloading...
await LoadCameras(); // Must reload entities
Entity newCamera = engine.GetEntity(someCameraGuid);
Console.WriteLine(ReferenceEquals(camera, newCamera)); // False - different instances!
Console.WriteLine(camera.IsDisposed); // True - old reference still disposed
Console.WriteLine(newCamera.IsDisposed); // False - new instance is active
Console.WriteLine(newCamera.Name); // "Camera 01" - actual name restoredWhen an entity changes (locally or remotely), the cache updates the single object instance. Any references you hold to that entity will automatically reflect the changes because they all point to the same object.
When you create an Engine instance, the cache is empty:
using var engine = new Engine();
// Cache is empty at this pointAfter successful authentication, some entities are automatically loaded into the cache:
ConnectionStateCode state = await engine.LogOnAsync(server, username, password);
// Cache now contains system entities like User, Role, Server, etc.Entity types typically loaded automatically:
- Application (the SDK client application)
- Network (associated with connected servers)
- Partition (root partition)
- Role (directory failover role)
- Server (connected directory server and failover servers)
- SystemConfiguration
- User (logged-in user)
- UserGroup (parent groups of logged-in user)
Note: The exact entities loaded depend on your system configuration and user privileges.
These system entities are loaded automatically because they're essential for the SDK to function properly. This also means you'll receive notifications for changes to these entities without needing to explicitly query for them.
Entities are loaded into the cache through queries. This step is crucial because it also registers your interest in those entity types with the server:
async Task LoadCameras()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
}Important: By querying for a specific entity type, you're telling the server "I want to know about all cameras, including new ones created later."
The Engine provides three batched events to notify you about cache changes. These events tell you about cache operations, not necessarily system operations.
Note
The single-entity events (EntityAdded, EntityInvalidated, EntityRemoved) are deprecated. Use the batched versions (EntitiesAdded, EntitiesInvalidated, EntitiesRemoved) for better scalability.
Fired when entities are added to the cache:
engine.EntitiesAdded += (sender, e) =>
{
foreach (EntityUpdateInfo info in e.Entities)
{
Entity entity = engine.GetEntity(info.EntityGuid);
Console.WriteLine($"Added to cache: {entity.Name} (Local: {e.IsLocalUpdate})");
}
};When this fires:
- During initial query execution (IsLocalUpdate = false)
- When you create a new entity locally (IsLocalUpdate = true)
- When another client creates a new entity (IsLocalUpdate = false)
Fired after entities have been updated in the cache:
engine.EntitiesInvalidated += (sender, e) =>
{
foreach (EntityUpdateInfo info in e.Entities)
{
Entity entity = engine.GetEntity(info.EntityGuid);
// The entity object already has the updated properties
Console.WriteLine($"Updated in cache: {entity.Name} (Local: {e.IsLocalUpdate})");
}
};When this fires:
- Immediately when you modify an entity locally (IsLocalUpdate = true)
- When another client modifies an entity and the change is committed to the server (IsLocalUpdate = false)
Fired when entities are removed from the cache:
engine.EntitiesRemoved += (sender, e) =>
{
foreach (EntityUpdateInfo info in e.Entities)
{
// The entity is already gone from the cache at this point
// GetEntity() will always return null here
Entity entity = engine.GetEntity(info.EntityGuid); // Always null!
Console.WriteLine($"Removed from cache: {info.EntityType} {info.EntityGuid}");
}
};When this fires: Only when entities are deleted from the system (there's no other mechanism to remove entities from cache).
Important: Since the entity has already been removed from the cache, calling GetEntity() in this event handler will always return null.
The IsLocalUpdate property is available on the event args (not on EntityUpdateInfo). It tells you the source of the change:
- True: Change was made through this same Engine instance
- False: Change came from somewhere else (Config Tool, Security Desk, another SDK application, system roles, etc.)
engine.EntitiesInvalidated += (sender, e) =>
{
if (e.IsLocalUpdate)
{
// Change originated from this Engine instance
}
else
{
// Change came from another client or system role
}
};Important: From the Directory Server's perspective, everything is a "client": your SDK app, Config Tool, Security Desk, and all system roles.
Understanding when events fire is crucial:
- Local changes: Events fire immediately when you make the change (before server commitment)
- Remote changes: Events fire after the change has been committed to the Directory Server
No Rollback Notification: If a local change fails to commit to the server, there's no automatic notification about the failure.
async Task LoadCameras()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
}async Task LoadCamerasWithRelatedData()
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.DownloadAllRelatedData = true; // This loads related entities too
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
}What DownloadAllRelatedData does:
When set to true, the query downloads comprehensive entity data:
- All entity properties - Both common and type-specific properties are loaded immediately
- Membership information - Which groups the entity belongs to and which entities it contains
- Related entities - Dependent entities are loaded into the cache (see table below)
- Event-to-action associations - Configured actions for entity events
-
Custom fields - All custom field values (equivalent to setting
DownloadCustomFields = true)
When set to false (default):
- Common properties only - Name, Description, GUID, running status, partition membership
- Lazy loading - Type-specific properties are fetched on first access, triggering additional server requests
- No related entities - You must query related entities separately
- No memberships - Group membership data is not included
For certain entity types, DownloadAllRelatedData = true also loads related entities into the cache. These related entities do not appear in the query result DataTable but are available via GetEntity().
| When You Query | Related Entities Loaded |
|---|---|
| Cardholder | Credentials assigned to the cardholder |
| Visitor | Credentials assigned to the visitor |
| Camera | Video encoder device, streams |
| Door | Child entities (readers, REX devices) |
| Device | Access points using the device, streams |
| Schedule | Access rules using the schedule |
| Role | Agents assigned to the role |
| User | Applications logged in with this user |
| Network | Routes associated with the network |
| InterfaceModule | Child interface modules |
| SystemConfiguration | Custom events |
Entity types not listed above (such as Unit, Alarm, Area, Zone, Elevator, CardholderGroup, etc.) do not load related entities. For these types, DownloadAllRelatedData only affects property and membership loading.
When to use DownloadAllRelatedData = true:
- When you need type-specific properties for multiple entities
- When you need membership information (group members or parent groups)
- When you need related entities (credentials, devices, streams, etc.)
- When building a comprehensive view of entity relationships
When to keep it false:
- When you only need basic entity information (Name, GUID, Description)
- When querying large numbers of entities and only need common properties
- When optimizing for initial load time and network bandwidth
The StrictResults property controls whether the query result DataTable includes only entities that match your filter criteria.
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.DownloadAllRelatedData = true;
query.StrictResults = true; // Only cameras appear in resultsWhen StrictResults = true:
- The query result DataTable contains only GUIDs that match your filter criteria
- Related entities downloaded via
DownloadAllRelatedDataare still added to the cache but do not appear in the result DataTable
When StrictResults = false (default):
- The query result DataTable may include GUIDs for related entities in addition to the entities matching your filter
- This can be useful when you want to know which related entities were downloaded
When to use StrictResults = true:
- When iterating over query results and you only want entities matching your filter
- When using the result DataTable to build a list of specific entity types
In most cases, the default value is fine since you typically access entities through GetEntity() or GetEntities() rather than iterating the result DataTable directly.
You can also load specific entities if you already know their GUIDs:
async Task LoadSpecificEntities(Engine engine, IEnumerable<Guid> entityGuids)
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
// Add specific GUIDs to load
foreach (var guid in entityGuids)
{
query.EntityGuids.Add(guid);
}
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
}Important behaviors when using EntityGuids:
- Filters should not be used - When specifying EntityGuids, don't use EntityTypeFilter, Name, Description, or other filters since you're already targeting specific entities by their GUIDs
- Invalid GUIDs are skipped - the query loads only entities that actually exist
- No notification registration - this does not register interest for future notifications about those entity types
- Pagination doesn't work with EntityGuids - all specified GUIDs are processed in a single query (unlike EntityTypeFilter queries, which support pagination)
Performance consideration: Don't specify too many GUIDs in a single query. If you have a large number of entities to load, split them into multiple smaller queries to avoid performance issues.
For advanced scenarios, you can use a two-step approach to first get entity GUIDs, then selectively load them:
Step 1: Get only the GUIDs (nothing loaded into cache):
var guidQuery = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
guidQuery.EntityTypeFilter.Add(EntityType.Camera);
guidQuery.Name = "Lobby"; // Only cameras whose names contain "Lobby"
guidQuery.GuidsOnly = true; // Only return GUIDs, don't load into cache
var guidResults = await Task.Factory.FromAsync(guidQuery.BeginQuery, guidQuery.EndQuery, null);Step 2: Use those GUIDs to load actual entities:
var loadQuery = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
// Add the GUIDs from step 1
foreach (DataRow row in guidResults.Data.Rows)
{
loadQuery.EntityGuids.Add(row.Field<Guid>("Guid"));
}
loadQuery.DownloadAllRelatedData = true;
await Task.Factory.FromAsync(loadQuery.BeginQuery, loadQuery.EndQuery, null);This pattern is useful when you want to apply complex filters first, then decide which entities to actually load into the cache.
When using pagination, entities are loaded per page:
async Task LoadEntitiesWithPagination(Engine engine, params EntityType[] types)
{
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.AddRange(types);
query.DownloadAllRelatedData = true;
query.Page = 1;
query.PageSize = 1000;
QueryCompletedEventArgs args;
do
{
// Entities from this page are immediately added to the cache
// and trigger EntitiesAdded events
args = await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
query.Page++;
} while (args.Data.Rows.Count >= query.PageSize);
}// Default behavior, will query server if not in cache
Entity entity = engine.GetEntity(entityGuid);
// Using logical ID and entity type
Entity entity = engine.GetEntity(EntityType.Camera, logicalId);
// Explicit control over querying behavior
Entity entity = engine.GetEntity(entityGuid, query: true); // Will query server if not cached
Entity entity = engine.GetEntity(entityGuid, query: false); // Only returns if already cached
// Generic versions for type safety (avoid casting)
Camera camera = engine.GetEntity<Camera>(cameraGuid);
Camera camera = engine.GetEntity<Camera>(cameraGuid, query: true);
Camera camera = engine.GetEntity<Camera>(cameraGuid, query: false);Important distinction:
-
GetEntity(guid)orGetEntity(guid, true): If the entity is not in the cache, automatically queries the server to fetch it and adds it to the cache -
GetEntity(guid, false): Returns entity only if already cached, null otherwise -
GetEntity(EntityType, logicalId): Behaves like the defaultGetEntity(guid), will query server if not cached
Note:
- When
GetEntity()fetches an entity from the server, it will trigger an EntitiesAdded event - However,
GetEntity()does not register interest in that entity type for future notifications - Only EntityConfigurationQuery and specialized queries register for notifications about new entities of those types created by other clients
// Option 1: Non-generic with cast
var cameras = engine.GetEntities(EntityType.Camera).OfType<Camera>().ToList();
// Option 2: Generic overload (preferred)
var cameras = engine.GetEntities<Camera>(EntityType.Camera);Important: GetEntities() always returns entities that are already in the cache. It will not query the server to fetch entities that aren't cached.
Remember: Multiple calls return references to the same object instances.
Entity properties are divided into two categories:
Common Properties (always loaded):
- Name, Description, Logical ID, GUID, CreatedOn
- These are shared by all entity types and are always loaded when calling
GetEntity()or executing any query
Specific Properties (lazy loaded):
- FirstName, LastName (for Cardholders)
- Email, MobilePhoneNumber (for Cardholders)
- Recipients (for Alarms)
- Camera-specific capabilities and settings
- These are specific to each entity type and require special handling
When you use GetEntity() or run a query with DownloadAllRelatedData = false:
// This loads only common properties
Cardholder cardholder = engine.GetEntity(cardholderGuid) as Cardholder;
// This triggers an internal query to load ALL specific properties for this cardholder
string firstName = cardholder.FirstName; // Internal query happens here
string lastName = cardholder.LastName; // No additional query, already loaded aboveImportant: GetEntity() does not have a DownloadAllRelatedData option. It always behaves like DownloadAllRelatedData = false.
To prevent multiple internal queries, use EntityConfigurationQuery with DownloadAllRelatedData = true:
// This loads both common AND specific properties upfront
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Cardholder);
query.DownloadAllRelatedData = true; // Critical for performance!
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
// Now accessing specific properties won't trigger additional queries
var cardholders = engine.GetEntities(EntityType.Cardholder).OfType<Cardholder>();
foreach (var cardholder in cardholders)
{
// These accesses are fast, no internal queries
string fullName = $"{cardholder.FirstName} {cardholder.LastName}";
}Bad Pattern (causes many internal queries):
// Don't do this, each FirstName access triggers an internal query
for (int i = 0; i < 100; i++)
{
Cardholder cardholder = engine.GetEntity(cardholderGuids[i]) as Cardholder;
string name = cardholder.FirstName; // Internal query for each iteration
}Good Pattern (one query loads everything):
// Do this instead, load all cardholders with specific properties upfront
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Cardholder);
query.DownloadAllRelatedData = true;
// Add specific GUIDs if needed
foreach (var guid in cardholderGuids)
{
query.EntityGuids.Add(guid);
}
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
// Now all accesses are fast
foreach (var guid in cardholderGuids)
{
Cardholder cardholder = engine.GetEntity(guid) as Cardholder;
string name = cardholder.FirstName; // Fast, no additional query
}While EntityConfigurationQuery is the most common way to load entities, the SDK also provides specialized query types that offer entity-specific filters and functionality:
CardholderConfigurationQuery: Provides cardholder-specific filters like:
- FirstName, LastName, FullName filtering with search modes and sorting
- Email, MobilePhoneNumber filtering with search modes
- AccessStatus filtering (Active, Expired, Inactive)
- CardholderGroupIds filtering
- ActivationTimeRange and ExpirationTimeRange
- VisitorsOnly filtering (true/false/null for both)
CredentialConfigurationQuery: Offers credential-specific options:
- UniqueIds collection for searching specific credentials
- FormatType filtering for credential formats
- UnassignedOnly filtering
- MobileCredentialOnly filtering
UserConfigurationQuery: Provides user-specific filters:
- FirstName, LastName filtering with search modes
- Email filtering
- Status filtering (Activated, Deactivated)
- UserGroupIds filtering
- SecurityLevel range filtering
- GroupRecursive search option
AccessRuleConfigurationQuery: Offers access rule filtering:
- AccessRuleType filtering
Consider using specialized queries when:
- You need entity-specific filtering that EntityConfigurationQuery doesn't provide
- You're working extensively with one entity type and need its specialized features
- You want more intuitive, type-specific property names and filters
Example:
// Using specialized query for advanced cardholder filtering
var cardholderQuery = (CardholderConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.CardholderConfiguration);
// Set cardholder-specific filters
cardholderQuery.FirstName = "John";
cardholderQuery.FirstNameSearchMode = StringSearchMode.StartsWith;
cardholderQuery.AccessStatus.Add(CardholderState.Active);
cardholderQuery.VisitorsOnly = false; // Only regular cardholders, not visitors
cardholderQuery.DownloadAllRelatedData = true;
await Task.Factory.FromAsync(cardholderQuery.BeginQuery, cardholderQuery.EndQuery, null);Tip: Check the SDK documentation for specialized query types for the entities you work with most frequently.
To receive notifications about new entities created by other clients, you must have queried for that entity type at least once. The query filters don't matter; just querying for the type registers your interest with the server.
// This enables notifications for ALL new cameras, regardless of the filter
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Camera);
query.Name = "Some Specific Camera"; // Restrictive filter
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
// Now you'll get EntitiesAdded events for any new cameras created by other clientsModifying one entity can trigger EntitiesInvalidated events for multiple related entities due to relationships. All entities in a cascade will have the same IsLocalUpdate value.
- Memory usage is the primary constraint for the cache
- There's no way to selectively remove entities from the cache
- The only way to clear the cache is to disconnect the Engine (but this is overkill unless you're truly done)
- Be thoughtful about which entity types you load
Even if entities are already cached, running another query will:
- Always execute the SQL query on the server - this is important to understand
- Not fire duplicate EntitiesAdded events for already-cached entities
- Update the cache if any entities have changed since they were last loaded
This means EntityConfigurationQuery always hits the server, regardless of what's in your cache.
When the Engine loses connection:
- The cache is immediately cleared - GetEntity() and GetEntities() calls will no longer work
-
Existing entity references continue to point to disposed objects with
IsDisposed = true - Upon reconnection, you must manually re-execute queries to repopulate the cache
// Register interest in cameras
await LoadCameras();
// Now you'll get notifications for all camera changes
engine.EntitiesAdded += (sender, e) =>
{
foreach (var info in e.Entities.Where(i => i.EntityType == EntityType.Camera))
{
Console.WriteLine($"New camera: {engine.GetEntity(info.EntityGuid).Name}");
}
};// Get a reference to an entity
Camera camera = engine.GetEntities(EntityType.Camera).OfType<Camera>().First();
// This reference will automatically reflect updates
// No need to call GetEntity() again after EntitiesInvalidated eventsvoid PrintEntityCache(Engine engine)
{
Console.WriteLine("===== Entity Cache Summary =====");
int totalEntities = 0;
foreach (var entityType in Enum.GetValues(typeof(EntityType))
.OfType<EntityType>()
.Where(t => t != EntityType.None && t != EntityType.ReportTemplate)
.OrderBy(t => t.ToString()))
{
int count = engine.GetEntities(entityType).Count;
totalEntities += count;
if (count > 0)
{
Console.WriteLine($"{entityType}: {count:N0}");
}
}
Console.WriteLine($"Total entities: {totalEntities:N0}");
}-
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.