Skip to content

platform sdk getting started

Andre Lafleur edited this page Mar 21, 2026 · 3 revisions

Connecting to Security Center

This guide shows how to connect a Platform SDK application to Security Center using the Engine class. The Engine manages the connection lifecycle and provides access to all SDK services.

Prerequisites

Before connecting to Security Center, verify:

  • Security Center SDK is installed on the machine
  • SDK certificate is configured (see Certificate placement)
  • Security Center license includes your certificate's part number
  • User account has "Log on using the SDK" privilege
  • Network access to the Security Center Directory server

Certificate placement

The SDK certificate file must be in a folder named Certificates at the same directory level as your application executable. The certificate file name must match your executable name with .cert appended.

Example folder structure:

MyApplication/
├── MyApp.exe
└── Certificates/
    └── MyApp.exe.cert

The SDK automatically searches for the certificate in this location when connecting to Security Center. If the certificate is missing, the connection fails with CertificateRegistrationError.

Alternatively, set the ClientCertificate property before connecting:

engine.ClientCertificate = "KxsD11z743Hf5Gq9mv3+5ekxzemlCiUXkTFY5ba1NOGcLCmGstt2n0zYE9NsNimv";

For certificate details and licensing requirements, see SDK Certificates.

Creating an Engine instance

The Engine class is the main entry point for all SDK operations. Create an instance using the using statement to ensure proper disposal:

using Genetec.Sdk;

using var engine = new Engine();

The Engine implements IDisposable. When disposed, it automatically logs off from Security Center (if connected) and releases all resources.

Automatic logoff on disposal

The Dispose method automatically calls LogOff when the Engine is disposed. This ensures:

  • Active connections are properly terminated
  • Server resources are released
  • Certificates are unregistered from the connection

You do not need to explicitly call LogOff before disposing the Engine. The using statement handles both operations:

using var engine = new Engine();
await engine.LogOnAsync(server, username, password);
// Work with engine...
// Dispose automatically logs off and cleans up

To manually log off while keeping the Engine instance alive, call LogOff explicitly:

var engine = new Engine();
try
{
    await engine.LogOnAsync(server, username, password);
    // Work with engine...
    engine.LogOff(); // Explicit logoff
    // Engine instance still usable for reconnection
}
finally
{
    engine.Dispose(); // Final cleanup
}

Understanding Engine and LoginManager

The Engine class exposes logon methods directly for convenience, but these methods delegate to the LoginManager property internally. Both approaches are functionally equivalent:

// These are equivalent:
await engine.LogOnAsync(server, username, password);
await engine.LoginManager.LogOnAsync(server, username, password);

When to use Engine methods:

Use engine.LogOnAsync() directly for cleaner code. This is the standard pattern for SDK applications.

When to use LoginManager methods:

Access engine.LoginManager when you need to:

  • Subscribe to connection events (LogonStatusChanged, LoggedOn, LogonFailed)
  • Access connection properties (IsConnected, ActualDirectoryEndPoint)
  • Configure connection behavior (ConnectionRetry, PreventDirectoryRedirection)

The Engine class exposes commonly used LoginManager properties (like IsConnected) directly, but all properties and events are available through engine.LoginManager.

Choosing a connection method

The SDK provides multiple logon methods organized into three categories, all accessible from both Engine and LoginManager:

Modern async methods (recommended)

LogOnAsync method family returns Task<ConnectionStateCode> for use with async/await:

ConnectionStateCode result = await engine.LogOnAsync(server, username, password);

These methods:

  • Return the connection result directly as a ConnectionStateCode
  • Support CancellationToken for cooperative cancellation
  • Follow modern .NET async patterns
  • Are non-blocking and efficient

Use these methods for all new SDK applications.

Legacy APM methods

BeginLogOn and EndLogOn methods implement the Asynchronous Programming Model (APM) from .NET Framework 2.0:

IAsyncResult asyncResult = engine.BeginLogOn(server, username, password);
// ... wait for completion
engine.EndLogOn(asyncResult);

These methods:

  • Return IAsyncResult (specifically LogOnAsyncResult) for tracking operation status
  • Use callback patterns instead of async/await
  • Require subscribing to events to determine success or failure
  • Do not return ConnectionStateCode values
  • Exist for backward compatibility only

The IAsyncResult returned by BeginLogOn provides:

  • IsCompleted property indicating whether the logon operation finished
  • AsyncWaitHandle property (ManualResetEvent) for blocking until completion

The SDK sets IsCompleted to true when:

  • The logon succeeds (LoggedOn event fires)
  • The logon is cancelled (LoggedOff event fires)

The SDK does not set IsCompleted to true when logon fails (LogonFailed event fires). This is a known limitation in the APM implementation.

Important

The EndLogOn method does not wait for the operation to complete. Instead, it cancels the logon operation by calling LogOff internally.

Do not use AsyncWaitHandle.WaitOne() to wait for completion. The wait handle never signals on logon failures, causing indefinite blocking. Always subscribe to the LoggedOn, LoggedOff, and LogonFailed events to handle all outcomes:

engine.LoginManager.LoggedOn += (s, e) => { /* Success */ };
engine.LoginManager.LoggedOff += (s, e) => { /* Cancelled */ };
engine.LoginManager.LogonFailed += (s, e) => { /* Failed */ };

IAsyncResult result = engine.BeginLogOn(server, username, password);
// Do NOT use result.AsyncWaitHandle.WaitOne() - it doesn't signal on failure

Do not use these methods in new code. They are less efficient and harder to maintain than async/await.

Legacy synchronous methods

LogOn and LogOnUsingWindowsCredential methods block the calling thread until connection completes:

engine.LogOn(server, username, password);
// Thread blocks here until connection succeeds or fails

These methods:

  • Block the calling thread for the entire connection duration (potentially several seconds)
  • Do not return ConnectionStateCode values
  • Require subscribing to events to determine success or failure
  • Provide explicit port parameter overloads

Use synchronous methods only when maintaining legacy code that cannot be refactored to async/await.

Legacy method compatibility table

All three method families support the same authentication modes:

Feature LogOnAsync BeginLogOn LogOn
Username and password
Windows credential
Security token
Supervisor credentials
Custom port ✓ (via server string) ✓ (port parameter) ✓ (port parameter)
Certificate parameter

Custom port syntax:

All methods support custom ports. Specify the port in the server string for all methods:

await engine.LogOnAsync("server:5501", username, password);

The BeginLogOn and LogOn methods also provide explicit port parameter overloads:

engine.LogOn("server", username, password, port: 5501);

Avoid legacy patterns:

Do not write polling loops. This is a common antipattern with APM methods:

// ❌ WRONG - Do not do this
engine.BeginLogOn(server, username, password);
while (!engine.IsConnected)
{
    Thread.Sleep(100); // Busy waiting wastes resources
}

This pattern is inefficient, blocks threads unnecessarily, and ignores connection failures.

Use async/await with LogOnAsync:

// ✅ CORRECT
ConnectionStateCode result = await engine.LogOnAsync(server, username, password);

if (result == ConnectionStateCode.Success)
{
    // Connected successfully
}
else
{
    // Handle specific failure
    Console.WriteLine($"Connection failed: {result}");
}

The async/await pattern is non-blocking, returns the result directly, and integrates with modern C# cancellation and error handling.

Connecting to Security Center

Use LogOnAsync to connect to the Directory:

ConnectionStateCode result = await engine.LogOnAsync(
    "directory-server",
    "username",
    "password");

if (result == ConnectionStateCode.Success)
{
    // Connection succeeded
}

Connecting when already connected

Calling LogOn while already connected throws InvalidOperationException.
Calling LogOnAsync while already connected throws SdkException (SdkError.CouldNotLogon) with an inner InvalidOperationException. The SDK checks the connection state and prevents duplicate login attempts.

To reconnect with different credentials or to a different server, call LogOff first:

if (engine.IsConnected)
{
    engine.LogOff();
}
await engine.LogOnAsync(server, username, password);

Connection parameters

Server address

The first parameter specifies the Directory server. Pass:

  • A hostname: "sc-server"
  • An IP address: "192.168.1.100"
  • An empty string to connect to localhost

Credentials

Standard authentication uses a Security Center username and password. The user must have the "Log on using the SDK" privilege.

Domain user authentication

To authenticate as a domain user from an Active Directory integration, specify the domain in the username parameter using either:

  • User Principal Name format: johnDoe@domain.com
  • Down-Level Logon Name format: domain\johnDoe
// Active Directory user authentication
ConnectionStateCode result = await engine.LogOnAsync(
    "directory-server",
    "johnDoe@domain.com",
    "password");

Domain credentials with LogOn

When you pass domain\username or user@domain to LogOn/LogOnAsync, the SDK uses password-based domain credentials (not Windows integrated auth).
For Windows integrated authentication, use LogOnUsingWindowsCredential*.

Security Center requires an Active Directory role configured for domain authentication.

Windows authentication

For Windows authentication, use LogOnUsingWindowsCredentialAsync to authenticate with the current Windows identity:

ConnectionStateCode result = await engine.LogOnUsingWindowsCredentialAsync(
    "directory-server");

This method:

  • Uses the Windows identity of the process running the SDK
  • Does not require passing credentials as parameters
  • Enhances security by avoiding credential handling in code

Security Center requires an Active Directory role configured for Windows authentication.

Handling connection results

The LogOnAsync method returns a ConnectionStateCode enum value. Check the result before proceeding:

ConnectionStateCode result = await engine.LogOnAsync(server, username, password);

switch (result)
{
    case ConnectionStateCode.Success:
        // Proceed with SDK operations
        break;
        
    case ConnectionStateCode.InvalidCredential:
        Console.WriteLine("Invalid username or password");
        break;
        
    case ConnectionStateCode.InsufficientPrivileges:
        Console.WriteLine("User lacks 'Log on using the SDK' privilege");
        break;
        
    case ConnectionStateCode.CertificateRegistrationError:
        Console.WriteLine("SDK certificate registration failed. Check the certificate file, license inclusion, certificate count, and application ID.");
        break;
        
    case ConnectionStateCode.LicenseError:
        Console.WriteLine("License does not include the SDK certificate part number");
        break;
        
    default:
        Console.WriteLine($"Connection failed: {result}");
        break;
}

Common failure codes:

Code Meaning
InvalidCredential Username or password is incorrect
InsufficientPrivileges User account lacks "Log on using the SDK" privilege
CertificateRegistrationError SDK certificate registration failed (missing or invalid file, certificate not included in the license, certificate count exceeded, or invalid application ID)
LicenseError License does not include the certificate's part number or connection limit exceeded
InvalidVersion SDK version is incompatible with the Security Center server
Timeout Connection attempt timed out

Subscribing to connection events

Subscribe to connection events to track progress and handle failures:

engine.LoginManager.LogonStatusChanged += (sender, e) => 
{
    Console.WriteLine($"Connection status: {e.Status}");
};

engine.LoginManager.LoggedOn += (sender, e) => 
{
    Console.WriteLine($"Logged on to '{e.ServerName}' as '{e.UserName}'");
};

engine.LoginManager.LogonFailed += (sender, e) => 
{
    Console.WriteLine($"Logon failed: {e.FormattedErrorMessage}");
    Console.WriteLine($"Error code: {e.FailureCode}");
};

Register event handlers before calling LogOnAsync to capture all status changes.

Validating the Directory certificate

Security Center uses TLS/SSL to encrypt communication between the SDK and the Directory. When connecting for the first time, or when the Directory's certificate has not been accepted yet, the RequestDirectoryCertificateValidation event fires:

engine.LoginManager.RequestDirectoryCertificateValidation += (sender, e) =>
{
    Console.WriteLine($"Directory: {e.DirectoryHostName}");
    Console.WriteLine($"Endpoint: {e.DirectoryEndPoint}");
    Console.WriteLine($"Certificate Subject: {e.DirectoryCertificate.Subject}");
    Console.WriteLine($"Certificate Issuer: {e.DirectoryCertificate.Issuer}");
    Console.WriteLine($"Valid From: {e.DirectoryCertificate.NotBefore}");
    Console.WriteLine($"Valid Until: {e.DirectoryCertificate.NotAfter}");
    Console.WriteLine($"Thumbprint: {e.DirectoryCertificate.Thumbprint}");

    if (e.CertificateRevoked)
        Console.WriteLine("Warning: Certificate is revoked");
    if (e.CertificateExpired)
        Console.WriteLine("Warning: Certificate is expired");
    if (e.CertificateIsUntrustedRoot)
        Console.WriteLine("Warning: Certificate has an untrusted root");
    if (e.CertificateDnsMismatch)
        Console.WriteLine("Warning: DNS name mismatch");

    // Set to true to accept the certificate
    e.AcceptDirectory = true;
};

The event fires once per Windows user per computer per certificate. After accepting a certificate, the system stores the acceptance decision and does not prompt again.

Note

This event validates the Secure Communication Certificate used for TLS/SSL encryption. This is separate from the SDK certificate that controls which applications can connect.

Register this event handler before calling LogOnAsync.

Connection progress tracking

The LogonStatusChanged event fires multiple times during connection. Use it to display progress:

engine.LoginManager.LogonStatusChanged += (sender, e) => 
{
    switch (e.Status)
    {
        case ConnectionStateCode.Connecting:
            Console.WriteLine("Connecting to Directory...");
            break;
            
        case ConnectionStateCode.ConnectionEstablished:
            Console.WriteLine("Connection established, authenticating...");
            break;
            
        case ConnectionStateCode.Success:
            Console.WriteLine("Authentication successful");
            break;
    }
};

Cancelling connection attempts

Pass a CancellationToken to allow cancellation:

using var cancellationTokenSource = new CancellationTokenSource();

// Cancel after 30 seconds
cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(30));

ConnectionStateCode result = await engine.LogOnAsync(
    server, 
    username, 
    password, 
    cancellationTokenSource.Token);

if (result == ConnectionStateCode.LogonAborted)
{
    Console.WriteLine("Connection attempt was cancelled");
}

Checking connection state

Use IsConnected to check if the Engine is currently connected:

if (engine.IsConnected)
{
    // Safe to perform SDK operations
}

Server endpoint information

Security Center load balancing may redirect connections across Directory servers. Two properties track endpoint information:

OriginalDirectoryEndpoint - The server address you provided to the logon method:

Console.WriteLine($"Requested server: {engine.OriginalDirectoryEndpoint}");

ActualDirectoryEndPoint - The server where you are actually connected:

Console.WriteLine($"Connected to: {engine.ActualDirectoryEndPoint}");

These values differ when load balancing redirects the connection to a different Directory server.

Accessing the logged user

After successful connection, the LoggedUser property provides access to the authenticated user entity:

User currentUser = engine.LoggedUser;
Console.WriteLine($"User: {currentUser.Name}");
Console.WriteLine($"Email: {currentUser.EmailAddress}");
Console.WriteLine($"User GUID: {currentUser.Guid}");

// Check user privileges
foreach (var privilege in currentUser.Privileges)
{
    Console.WriteLine($"Privilege: {privilege.PrivilegeGuid}, State: {privilege.State}");
}

This property returns null when not connected.

Application entity

When a client signs in to the Directory, Security Center creates an Application entity (EntityType.Application) that represents the connection. Every client that connects to the Directory has its own Application entity. This includes operator workstations running Security Desk or Config Tool, server roles such as Access Manager, Federation, and Mobile Server, and external integrations built with the Platform SDK.

The ApplicationType property identifies the type of client:

Value Description
Sdk An application built with the Platform SDK.
SecurityDesk A Security Desk operator workstation.
ConfigTool A Config Tool administration application.
AccessManager An Access Manager server role.
Federation A Security Center Federation role.
MobileServer A Security Center Mobile Server role.
WebClient A Web Client application.
IntegrationService An Integration Service role.

The enumeration includes additional values for other client types such as MobileClient, RoamingFederation, SaasOperation, and others.

The Application entity exposes:

Property Type Description
ApplicationType ApplicationType The type of client.
LoggedUser User The user entity signed in to this application.
LoggedUserGuid Guid The GUID of the signed-in user.
Monitors ReadOnlyCollection<Guid> The GUIDs of Monitor entities registered by this application. Security Desk registers one monitor per display.
ApplicationVersion string The version of the client application.
Name string The workstation and application name (for example, "WS01 - SecurityDesk"). Inherited from Entity.

The entity Name follows the format "WORKSTATION - APPLICATION", where WORKSTATION is the machine name and APPLICATION is the client type (for example, "SecurityDesk").

The Engine provides two properties to access your own Application entity:

Application myApp = engine.Client;
Guid myAppGuid = engine.ClientGuid;

To discover other applications connected to the system, query for them using EntityConfigurationQuery. The GetEntities method returns cached entities only. For details on how the entity cache works, see About the Engine entity cache.

var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.Application);
query.DownloadAllRelatedData = true;
await Task.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);

var applications = engine.GetEntities(EntityType.Application).OfType<Application>();

foreach (Application app in applications)
{
    Console.WriteLine($"{app.Name} ({app.ApplicationType}) - Online: {app.IsOnline}");
}

When a client disconnects, its Application entity is not deleted. The entity's RunningState transitions to State.NotRunning and its IsOnline property returns false. These properties are inherited from the Entity base class and are available on all entity types.

Property Type Description
IsOnline bool true when RunningState is Running or Warning, false when NotRunning.
RunningState State The running state of the entity: Running, NotRunning, or Warning.

Disconnecting from Security Center

Call LogOff to disconnect from the Directory:

engine.LogOff();

For async operations, use BeginLogOff:

engine.LoginManager.BeginLogOff();

The LoggingOff event fires when disconnection starts. The LoggedOff event fires when complete:

engine.LoginManager.LoggingOff += (sender, e) => 
{
    Console.WriteLine("Disconnecting...");
};

engine.LoginManager.LoggedOff += (sender, e) => 
{
    Console.WriteLine("Disconnected from Security Center");
    Console.WriteLine($"Auto-reconnect: {e.AutoReconnect}");
};

Calling LogOff when disconnected

Calling LogOff when already disconnected is safe. The method:

  • Checks the connection state internally
  • Only waits for the LoggedOff event if previously connected
  • Completes immediately if no connection exists
  • Does not throw exceptions for redundant calls

This allows calling LogOff defensively without checking IsConnected first:

// Safe to call even when not connected
engine.LogOff();

Automatic logoff on disposal

Disposing the Engine automatically calls LogOff if still connected. The using statement handles both operations:

using var engine = new Engine();
await engine.LogOnAsync(server, username, password);
// Dispose automatically logs off and cleans up

Complete example

using Genetec.Sdk;

using var engine = new Engine();

// Subscribe to connection events
engine.LoginManager.LogonStatusChanged += (sender, e) => 
    Console.WriteLine($"Status: {e.Status}");

engine.LoginManager.LoggedOn += (sender, e) => 
    Console.WriteLine($"Connected to '{e.ServerName}' as '{e.UserName}'");

engine.LoginManager.LogonFailed += (sender, e) => 
    Console.WriteLine($"Connection failed: {e.FormattedErrorMessage}");

// Connect to Security Center
ConnectionStateCode result = await engine.LogOnAsync(
    "directory-server",
    "admin",
    "password");

if (result == ConnectionStateCode.Success)
{
    // Connection succeeded - perform SDK operations
    Console.WriteLine($"Connection state: {engine.IsConnected}");
    Console.WriteLine($"Server: {engine.ActualDirectoryEndPoint}");
    
    // Example: Access an entity
    var camera = engine.GetEntity(cameraGuid);
    
    // Disconnect when finished
    engine.LoginManager.BeginLogOff();
}
else
{
    Console.WriteLine($"Connection failed with result: {result}");
}

Supervised logon

Security Center supports supervised logon where a supervisor user authorizes another user's actions. Pass supervisor credentials to LogOnAsync:

ConnectionStateCode result = await engine.LogOnAsync(
    "directory-server",
    "operator-username",
    "operator-password",
    "supervisor-username",
    "supervisor-password");

Both users must exist in Security Center. The operator's actions execute with combined privileges from both accounts.

Federated authentication with external identity providers

When Security Center is configured to trust external identity providers such as SAML 2.0 or OpenID Connect, applications can authenticate users using security tokens issued by those providers. This enables Single Sign-On (SSO) scenarios where users authenticate once with their corporate credentials.

Prerequisites

Before using token-based authentication:

  1. Configure an Authentication Service role in Security Center (SAML 2.0 or OpenID Connect type)
  2. Configure the role with your identity provider's settings
  3. Obtain a security token from your identity provider after the user authenticates

The SDK does not provide methods to obtain tokens from identity providers. Token acquisition is handled by your identity provider's SDK or library.

Connecting with a security token

Pass the security token obtained from your identity provider to LogOnUsingSecurityTokenAsync:

// After obtaining a SecurityToken from your identity provider
ConnectionStateCode result = await engine.LogOnUsingSecurityTokenAsync(
    "directory-server",
    securityToken);

Or use the serialized token string directly:

// Using the serialized token string
ConnectionStateCode result = await engine.LogOnUsingSecurityTokenAsync(
    "directory-server",
    serializedTokenString);

Note

Serialized tokens must be Bearer tokens that do not require proof of possession.

Security Center validates the token against the configured Authentication Service role. When validation succeeds, the SDK connects with the user's identity and privileges from Security Center.

When to use token-based authentication

Use LogOnUsingSecurityTokenAsync for:

  • Single Sign-On (SSO) scenarios where users authenticate with corporate credentials
  • Federated authentication where Security Center trusts an external identity provider
  • Web applications that authenticate users via OAuth/OpenID Connect and connect to Security Center on behalf of the authenticated user

For standard username and password authentication, use LogOnAsync instead.

Connection reliability

The SDK includes built-in mechanisms to handle connection failures and network interruptions. Understanding these features prevents writing unnecessary reconnection logic.

Initial connection retry

When connecting, the SDK automatically retries failed attempts. The default is 10 retries. Configure this before calling LogOnAsync:

// Retry indefinitely until connection succeeds
engine.ConnectionRetry = -1;

// Try only once (no retries)
engine.ConnectionRetry = 1;

// Try 5 times before giving up
engine.ConnectionRetry = 5;

During these retry attempts, the SDK handles all connection logic internally. The LogOnAsync method returns only after all retry attempts are exhausted. The LogonStatusChanged event fires during retries to report connection progress. The LogonFailed event fires only when all retry attempts fail.

The retry mechanism applies to initial connection only. After a successful connection, the SDK handles network interruptions differently.

Automatic reconnection on connection loss

When a connection to Security Center is lost after being established, the SDK automatically attempts to reconnect. Check the AutoReconnect property in the LoggedOff event to determine if reconnection will occur:

engine.LoginManager.LoggedOff += (sender, e) => 
{
    if (e.AutoReconnect)
    {
        Console.WriteLine("Connection lost. SDK will automatically reconnect.");
    }
    else
    {
        Console.WriteLine("Disconnected. No automatic reconnection.");
    }
};

When AutoReconnect is true, the SDK reconnects in the background. The LoggedOn event fires again when reconnection succeeds. The LogonFailed event fires if reconnection fails.

Do not write custom reconnection logic. The SDK manages reconnection automatically. Simply handle the LoggedOn event to resume operations after reconnection.

Understanding transient vs permanent errors

The SDK distinguishes between transient errors that may resolve with retries and permanent errors that require fixing the underlying issue. This distinction determines which errors trigger automatic reconnection and which do not.

Transient errors (SDK retries automatically):

These errors indicate temporary problems that may resolve on subsequent attempts:

  • ConnectionLost - Network connection interrupted
  • Timeout or OperationTimeout - Connection attempt timed out
  • Failed - General connection failure
  • NoAuthenticationAgent - Active Directory role temporarily unavailable
  • AuthenticationAgentResponseTimeout - Active Directory did not respond in time
  • AuthenticationAgentImportFailure - Failed to import user from Active Directory
  • DeniedByFirewall - Firewall blocked the connection
  • DirectoryRedirect - Load balancer redirected to another Directory
  • NewConnection or NewBackupConnection - Connection status notifications

Permanent errors (SDK does not retry automatically):

These errors indicate configuration problems that will not resolve without changes:

  • InvalidCredential - Username or password is incorrect
  • InsufficientPrivileges - User lacks "Log on using the SDK" privilege
  • InsufficientSecurityLevel - User security level is too low
  • CertificateRegistrationError - SDK certificate is missing or invalid
  • LicenseError - License does not include certificate or connection limit exceeded
  • InvalidVersion - SDK version incompatible with Security Center
  • UserAccountDisabledOrLocked - User account is disabled or locked
  • PasswordExpired or ExternalPasswordExpired - User password requires reset
  • DisallowedBySchedule - User attempted logon outside allowed schedule
  • ExceededNumberOfWorkstations - User exceeded workstation limit
  • SpecifyDomain - Multiple Active Directory domains require explicit domain
  • DirectoryCertificateNotTrusted - Directory SSL certificate not accepted
  • InvalidSupervisor - Supervisor credentials are invalid
  • InteractiveLogonRequired - User must log on interactively
  • LogonAborted - Logon was cancelled
  • AlreadyConnected - Application is already connected
  • BruteForceThrottling - Account temporarily locked due to failed attempts

Note

The LicenseError behavior varies by application type. Config Tool and Security Desk do not auto-reconnect on license errors, but other applications may retry since licenses can change dynamically.

When building applications, check the ConnectionStateCode from LogOnAsync to determine if the error requires user action:

ConnectionStateCode result = await engine.LogOnAsync(server, username, password);

if (result == ConnectionStateCode.InvalidCredential || 
    result == ConnectionStateCode.InsufficientPrivileges ||
    result == ConnectionStateCode.UserAccountDisabledOrLocked)
{
    // Permanent errors - prompt user to fix credentials or contact administrator
    Console.WriteLine("Authentication failed. Please check your credentials.");
}
else if (result != ConnectionStateCode.Success)
{
    // Transient errors - may work if tried again later
    Console.WriteLine("Connection failed. Please try again.");
}

This distinction helps applications provide appropriate error messages and avoid wasteful retry attempts for permanent failures.

Understanding directory failover and load balancing

Security Center supports directory redundancy through failover directories and load balancing. The SDK handles these mechanisms automatically, requiring no manual intervention from client applications.

Directory load balancing:

When multiple Directory servers are configured in a Security Center system, the Directory Manager distributes connection requests across all available directories in a round-robin fashion. When a client connects, the Directory Manager may redirect the connection to a different Directory server.

During connection, the SDK handles redirection automatically:

  1. Client calls LogOnAsync with a Directory address
  2. Directory Manager evaluates available directories and may redirect to another server
  3. SDK receives DirectoryRedirect response and automatically connects to the redirected server
  4. LogonStatusChanged event fires with DirectoryRedirect status
  5. SDK completes connection to the redirected Directory
  6. LoggedOn event fires with the actual server name

The redirection is transparent. Applications do not need to handle DirectoryRedirect differently from other connection progress events.

Directory failover:

Security Center systems can include failover Directory servers configured in the Directory Manager role. When connection to the primary Directory is lost, the SDK automatically attempts to connect to a failover directory.

Critical: Failover requires successful initial connection

The failover directory list is obtained from the Directory Manager DURING the initial successful connection. The SDK stores this list internally for use if connection is lost later.

Connection scenarios:

  1. First connection succeeds:

    • SDK connects to primary Directory
    • Directory Manager sends list of configured failover directories
    • SDK stores the failover list in memory
    • If connection is lost later, SDK automatically tries failover directories from the stored list
  2. First connection fails (primary Directory unavailable):

    • SDK has no failover directory list yet
    • LogOnAsync returns connection failure (e.g., Timeout, Failed)
    • No automatic failover occurs
    • Application must handle initial connection failure
    • SDK retries the same primary directory address up to ConnectionRetry times

Where the failover list is stored:

The failover directory list is stored in two locations:

  • In memory: The SDK caches the list internally within the Engine instance for immediate use during automatic reconnection
  • On disk: The list is persisted to a configuration file in the local user's application data folder

When an SDK application connects successfully to Security Center, the Directory Manager provides the failover directory list. The SDK stores this list in a configuration file for future use. On subsequent application launches, if the primary Directory is unavailable, the SDK can attempt connection to failover directories using the previously cached list.

The configuration persists:

  • Between application restarts
  • Per Windows user account
  • In the local application data folder (typically %LOCALAPPDATA%\Genetec Security Center 5.X\)

Each Engine instance reads the cached failover list on startup. If the primary Directory is unavailable during initial connection, the SDK tries cached failover directories if available. After a successful connection to any Directory, the SDK updates the cached failover list with current configuration from the Directory Manager.

The failover process (after initial connection):

  1. Connection to primary Directory is lost (LoggedOff event fires with AutoReconnect=true)
  2. SDK automatically attempts to connect to each configured failover directory from the stored list
  3. LogonStatusChanged events fire during failover attempts
  4. When connection to failover directory succeeds, LoggedOn event fires
  5. Application resumes normal operation on the failover Directory

Initial connection reliability:

Since failover only works after the first successful connection, consider these approaches for initial connection reliability:

  1. Use ConnectionRetry property:

    engine.ConnectionRetry = -1; // Retry indefinitely until primary Directory responds
  2. Handle initial connection failure:

    ConnectionStateCode result = await engine.LogOnAsync(server, username, password);
    
    if (result != ConnectionStateCode.Success)
    {
        // Initial connection failed - no failover list available
        // Application must handle this (retry later, alert user, etc.)
        Console.WriteLine($"Cannot connect to Directory: {result}");
    }
  3. Use transient error detection:

    After all retry attempts are exhausted, check the ConnectionStateCode to distinguish transient errors from permanent ones:

    ConnectionStateCode result = await engine.LogOnAsync(server, username, password);
    
    if (result == ConnectionStateCode.Timeout || 
        result == ConnectionStateCode.Failed)
    {
        // Transient - may succeed later when server comes back
        Console.WriteLine("Unable to reach server. Check network connectivity.");
    }
    else if (result == ConnectionStateCode.InvalidCredential)
    {
        // Permanent - requires fixing credentials
        Console.WriteLine("Invalid username or password.");
    }

    See Antipatterns to avoid for common mistakes when handling connection failures.

No manual failover required:

Applications should not implement custom failover or retry logic. The SDK automatically manages failover after obtaining the directory list. Simply handle the LoggedOn event to resume operations after automatic failover completes.

Detecting which Directory you are connected to:

Use ActualDirectoryEndPoint to determine the current Directory server:

engine.LoginManager.LoggedOn += (sender, e) => 
{
    Console.WriteLine($"Connected to Directory: {e.ServerName}");
    Console.WriteLine($"Actual endpoint: {engine.ActualDirectoryEndPoint}");
    Console.WriteLine($"Original endpoint: {engine.OriginalDirectoryEndpoint}");
};

When load balancing redirects the connection or failover switches to a backup directory, ActualDirectoryEndPoint differs from OriginalDirectoryEndpoint.

Connection state during failover:

During failover, IsConnected returns false until connection to a failover directory succeeds. The LogonStatusChanged event reports progress during failover attempts.

Preventing load balancing and failover:

In rare cases where an application must connect to a specific Directory server, disable redirection and failover before logging on:

engine.PreventDirectoryRedirection = true;

ConnectionStateCode result = await engine.LogOnAsync(server, username, password);

This bypasses load balancing and prevents automatic failover. The SDK connects only to the specified Directory server. Use this setting only when specifically required, such as administrative tools that must interact with a particular Directory instance.

Note

Load balancing and failover are Security Center infrastructure features. Directory failover servers are configured in Config Tool under the Directory Manager role settings. The SDK automatically uses the failover configuration without requiring any setup in client applications. However, automatic failover only functions after a successful initial connection that retrieves the failover directory list.

Antipatterns to avoid

Do not write custom retry logic

❌ WRONG - Wrapping LogOnAsync in a retry loop:

// DO NOT DO THIS
int maxAttempts = 10;
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
    var result = await engine.LogOnAsync(server, username, password);
    
    if (result == ConnectionStateCode.Success)
        break;
        
    await Task.Delay(1000); // Wait before retrying
}

This creates a double-retry situation. The SDK already retries internally based on ConnectionRetry. Wrapping LogOnAsync in your own loop means if ConnectionRetry is 10, and your loop attempts 10 times, the application makes 100 connection attempts (10 × 10).

✅ CORRECT - Use the built-in ConnectionRetry property:

// Set the retry count once
engine.ConnectionRetry = 10;

// LogOnAsync handles all retries internally
var result = await engine.LogOnAsync(server, username, password);

The SDK manages timing, exponential backoff, and connection state internally. Custom retry logic interferes with this mechanism and wastes resources.

Do not poll IsConnected in a loop

❌ WRONG - Polling connection state after BeginLogOn:

// DO NOT DO THIS
engine.LoginManager.BeginLogOn(server, username, password);

while (!engine.IsConnected)
{
    Thread.Sleep(100);
}

This blocking pattern wastes CPU cycles and prevents the application from responding to user input. It also ignores connection failures, causing the loop to run indefinitely if logon fails.

✅ CORRECT - Use LogOnAsync with await:

var result = await engine.LogOnAsync(server, username, password);

if (result == ConnectionStateCode.Success)
{
    // Connection established
}

Or subscribe to events if using the synchronous LogOn method:

engine.LoginManager.LoggedOn += (sender, e) => 
{
    // Connection established
};

engine.LoginManager.LogonFailed += (sender, e) => 
{
    // Connection failed
};

engine.LogOn(server, username, password);

Do not write custom reconnection handlers

❌ WRONG - Manually calling LogOnAsync after connection loss:

// DO NOT DO THIS
engine.LoginManager.LoggedOff += async (sender, e) =>
{
    // Try to reconnect manually
    await engine.LogOnAsync(server, username, password);
};

The SDK automatically reconnects when e.AutoReconnect is true. Manual reconnection attempts interfere with the SDK's internal connection management and may cause multiple simultaneous connection attempts.

✅ CORRECT - Let the SDK handle reconnection:

engine.LoginManager.LoggedOff += (sender, e) =>
{
    if (e.AutoReconnect)
    {
        Console.WriteLine("SDK is reconnecting automatically");
    }
};

engine.LoginManager.LoggedOn += (sender, e) =>
{
    Console.WriteLine("Reconnection successful");
    // Resume normal operations
};

The SDK reconnects automatically and fires LoggedOn when reconnection succeeds.

Next steps

After connecting successfully:

Security Center SDK

  • Security Center SDK Developer Guide Overview of the SDK framework and how to build integrations with Security Center.

    • Platform SDK

      • Overview Introduction to the Platform SDK and core concepts.
      • Connecting to Security Center Step-by-step guide for connecting and authenticating with the SDK.
      • SDK Certificates Details certificates, licensing, and connection validation.
      • Referencing SDK Assemblies Best practices for referencing assemblies and resolving them at runtime.
      • SDK Compatibility Guide Understanding backward compatibility and versioning in the SDK.
      • Entity Guide Explains the core entity model, inheritance, and how to work with entities.
      • Entity Cache Guide Describes the engine's local entity cache and synchronization.
      • Transactions Covers batching operations for performance and consistency.
      • Events Subscribing to real-time system events.
      • Actions Sending actions to Security Center.
      • Security Desk Displaying content on monitors, reading tiles, sending tasks, and messaging operators.
      • Custom Events Defining, raising, and subscribing to custom events.
      • ReportManager Querying entities and activity data from Security Center.
      • ReportManager Query Reference Complete reference of query types, parameters, and response formats.
      • Privileges Checking, querying, and setting user privileges.
      • Partitions Entity organization and access control through partitions.
      • Logging How to configure logging, diagnostics, and debug methods.
    • Plugin SDK

    • Workspace SDK

    • Macro SDK

      • Overview How macros work, creating and configuring macro entities, automation, and monitoring.
      • Developer Guide Developing macro code with the UserMacro class and Security Center SDK.

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.
  • About access control in the Web SDK Concepts, relationships, and common access-control operations.
  • About video in the Web SDK Concepts, relationships, configuration, and common video operations.
  • Users and user groups Creating users, managing group membership, and assigning privileges.
  • Partitions Managing partitions, entity membership, and user access control.
  • Custom Fields Creating, reading, writing, and filtering custom entity fields.
  • Custom Card Formats Managing custom credential card format definitions.
  • Actions Control operations for doors, cameras, macros, and notifications.
  • Events and Alarms Real-time event monitoring, alarm monitoring, and custom events.
  • Incidents Incident management, creation, and attachment handling.
  • Reports Activity reports, entity queries, and historical data retrieval.
  • Tasks Listing and executing saved report tasks.
  • Macros Monitoring currently running macros.
  • Custom Entity Types Listing, retrieving, and deleting custom entity type descriptors.
  • System Endpoints License usage, web tokens, and exception handling.
  • Performance Guide Optimization tips and best practices for efficient API usage.
  • Reference Entity GUIDs, EntityType enumeration, and EventType enumeration.
  • Under the Hood Technical architecture, query reflection, and SDK internals.
  • Troubleshooting Common error resolution and debugging techniques.

Media Gateway Developer Guide


Web Player Developer Guide

  • Developer Guide Complete guide to integrating GWP for live and playback video streaming.
  • API Reference Full API documentation with interfaces, methods, properties, and events.
  • Sample Application Comprehensive demo showcasing all GWP features with timeline and PTZ controls.
  • Multiplexing Sample Multi-camera grid demo using a shared WebSocket connection.

Clone this wiki locally