Skip to content

platform sdk entity cache

Andre Lafleur edited this page Dec 11, 2025 · 1 revision

About the Engine 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.

Understanding entities in the SDK

Before diving into how the cache works, it's important to understand what entities are in the Genetec SDK context.

What is an Entity?

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.

Entity Identifiers

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) throws ArgumentOutOfRangeException if outside valid range

Entity Types and Inheritance

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 property

Common entity types include:

  • Camera, Door, Area, AccessPoint
  • Cardholder, CardholderGroup, Credential
  • Alarm, Schedule, AccessRule
  • Role, User, UserGroup
  • And many others

Entity Relationships

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.

Key Benefits

  • 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

How the Cache Works Internally

Thread Safety

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.

Single Instance Storage

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!

Multiple Engine Instances

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 GUID

Connection Loss and Entity Disposal

When the Engine loses connection to the server:

  • The cache is cleared - all entity objects are disposed and removed
  • GetEntity() will return null for 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 restored

Automatic Updates

When 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.

Entity Cache Lifecycle

1. Initial State

When you create an Engine instance, the cache is empty:

using var engine = new Engine();
// Cache is empty at this point

2. After Connection

After 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.

3. Loading Entities

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."

Understanding Cache Events

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.

1. EntitiesAdded Event

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)

2. EntitiesInvalidated Event

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)

3. EntitiesRemoved Event

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.

Understanding IsLocalUpdate

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.

Timing of Events

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.

Loading Entities and Related Data

Basic Loading

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);
}

Loading with Related Data

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

Related entities by entity type

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

Understanding StrictResults

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 results

When StrictResults = true:

  • The query result DataTable contains only GUIDs that match your filter criteria
  • Related entities downloaded via DownloadAllRelatedData are 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.

Loading Specific Entities by GUID

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.

Two-Step Loading Pattern with GuidsOnly

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.

Pagination Behavior

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);
}

Accessing Cached Entities

Get Individual Entity

// 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) or GetEntity(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 default GetEntity(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

Get All Entities of a Type

// 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.

Understanding Lazy Loading of Entity Properties

Common vs Specific Properties

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

How Lazy Loading Works

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 above

Important: GetEntity() does not have a DownloadAllRelatedData option. It always behaves like DownloadAllRelatedData = false.

Avoiding Lazy Loading Performance Issues

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}";
}

Performance Impact

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
}

Specialized Query Types

While EntityConfigurationQuery is the most common way to load entities, the SDK also provides specialized query types that offer entity-specific filters and functionality:

Examples of Specialized Queries

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

When to Use Specialized Queries

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.

Important Behaviors to Understand

1. Notification Registration

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 clients

2. Entity Relationship Cascades

Modifying one entity can trigger EntitiesInvalidated events for multiple related entities due to relationships. All entities in a cascade will have the same IsLocalUpdate value.

3. Memory Management

  • 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

4. Queries Always Execute

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.

5. Connection Loss

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

Common patterns

Monitor Specific Entity Types

// 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}");
    }
};

Working with Entity References

// 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 events

Monitoring Cache Status

void 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


Macro SDK Developer Guide


Web SDK Developer Guide

  • 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 Developer Guide


Web Player Developer Guide

Clone this wiki locally