-
Notifications
You must be signed in to change notification settings - Fork 4
plugin sdk database
Plugins can integrate with SQL Server for persistent storage. The database infrastructure is managed by Security Center through a state machine.
flowchart TB
A[Plugin Host Database Layer] --> B[Creates/Upgrades/Connects to SQL Server]
B --> C[Calls plugin's DatabaseManager methods]
C --> D[Plugin uses connection string for data access]
Database state machine:
stateDiagram-v2
[*] --> Startup
Startup --> Connected: Version valid
Startup --> WaitingForUpgrade: Version too old
Startup --> Disconnected: Connection failed or no DB
Disconnected --> Startup: Retry or recovered
Disconnected --> Creating: CreateDatabase or auto-create
Creating --> Startup: Create complete
Creating --> Error: Create failed
WaitingForUpgrade --> Upgrading: UpgradeDatabase
WaitingForUpgrade --> Disconnected: Connection lost
Upgrading --> Startup: Upgrade finished
Connected --> Disconnected: Connection lost
Connected --> BackingUp: BackupDatabase
Connected --> Restoring: RestoreDatabase
Connected --> Dropping: DropDatabase
Connected --> Cleanup: CleanupDatabase
Connected --> ResolvingConflicts: ResolveConflicts
BackingUp --> Connected: Backup complete (prev Connected)
BackingUp --> Startup: Backup complete (prev not Connected)
BackingUp --> Error: Backup failed
Restoring --> Startup: Restore complete
Restoring --> Error: Restore failed
Dropping --> Disconnected: Drop complete
Cleanup --> Startup: Cleanup complete
ResolvingConflicts --> Startup
Error --> Startup: Retry
Key concepts:
- Security Center manages database lifecycle
- Plugin provides schema and logic via DatabaseManager
- Each plugin role instance gets its own database
- Security Center provides database configuration for each role
- Supports SQL Server only (no other databases)
Implement IPluginDatabaseSupport interface:
public class MyPlugin : Plugin, IPluginDatabaseSupport
{
public DatabaseManager DatabaseManager => new MyDatabaseManager();
}Interface requirements:
- Must provide a
DatabaseManagerinstance - DatabaseManager defines schema, upgrades, and cleanup
- Security Center calls DatabaseManager methods at appropriate times
Create a class inheriting from DatabaseManager:
public class MyDatabaseManager : DatabaseManager
{
private DatabaseConfiguration m_config;
public override string GetSpecificCreationScript(string databaseName) { }
public override void SetDatabaseInformation(DatabaseConfiguration config) { }
public override void OnDatabaseStateChanged(DatabaseNotification notification) { }
public override IEnumerable<DatabaseCleanupThreshold> GetDatabaseCleanupThresholds() { }
public override void DatabaseCleanup(string name, int retentionPeriod) { }
public override IEnumerable<DatabaseUpgradeItem> GetDatabaseUpgradeItems() { }
}Controls whether the database is created in single-user mode:
public class MyDatabaseManager : DatabaseManager
{
// Override to disable single-user mode during database creation
public override bool UseSingleUserDatabaseCreation => false;
}Default value: true
When true (default):
- Database is created in single-user mode
- Prevents other connections during creation
- Provides exclusive access for schema setup
- Recommended for most scenarios
When false:
- Database is created in multi-user mode
- Other connections may access the database during creation
- Use when single-user mode causes issues with your database setup
The database layer starts after OnPluginLoaded() and before OnPluginStart():
flowchart TB
A[1. Plugin constructed] --> B["2. Plugin.Initialize(engine, roleGuid, culture)<br/>OnPluginLoaded() runs"]
B --> C{Implements IPluginDatabaseSupport?}
C -->|No| H1[3. OnPluginStart called]
C -->|Yes| D[3. DatabaseManager.SetDatabaseInformation]
D --> E["4. Database layer created<br/>reads GetDatabaseUpgradeItems()"]
E --> F[5. Database state machine starts]
F --> G["6. Creating state calls GetSpecificCreationScript()<br/>when database is missing"]
F --> I["7. Upgrading state runs upgrade items<br/>when version is behind"]
F --> J["8. OnDatabaseStateChanged notifications<br/>Startup, Disconnected, Creating, Upgrading, Connected, Error"]
F --> H2[9. OnPluginStart called]
Critical timing:
- In
OnPluginLoaded(), database may not be ready -
OnPluginStart()does not guaranteeDatabaseState.Connected - Use
OnDatabaseStateChanged()to wait forDatabaseState.Connected
See Plugin SDK Lifecycle for lifecycle details.
Called if database doesn't exist. Returns SQL to create tables and schema.
public override string GetSpecificCreationScript(string databaseName)
{
return $@"
CREATE TABLE [{databaseName}].[dbo].[EventLog] (
[Id] INT IDENTITY(1,1) PRIMARY KEY,
[Timestamp] DATETIME2 NOT NULL,
[EventType] NVARCHAR(50) NOT NULL,
[Description] NVARCHAR(MAX),
[EntityGuid] UNIQUEIDENTIFIER
);
CREATE INDEX IX_EventLog_Timestamp
ON [{databaseName}].[dbo].[EventLog]([Timestamp]);
CREATE TABLE [{databaseName}].[dbo].[Configuration] (
[Key] NVARCHAR(100) PRIMARY KEY,
[Value] NVARCHAR(MAX)
);
";
}Important
- Security Center supplies the database name
- Always use the
databaseNameparameter in your SQL - If the script fails, database creation fails
Called before the database layer starts and provides connection info.
public override void SetDatabaseInformation(DatabaseConfiguration config)
{
m_config = config;
// Use CreateSqlDatabaseConnection() for a ready-to-use connection
// or use ConnectionString + DatabaseCredential for manual connection creation
Logger.TraceInformation("Database connection configured");
}DatabaseConfiguration properties:
-
ConnectionString- SQL Server connection string (does not include credentials if using SqlCredential) -
DatabaseCredential- SqlCredential for authentication (null if using Windows integrated security) -
CreateSqlDatabaseConnection()- Creates a configured SqlConnection ready for use
When called:
- Before the database layer starts
- Before
OnPluginStart()
Called on database state transitions.
public override void OnDatabaseStateChanged(DatabaseNotification notification)
{
switch (notification.State)
{
case DatabaseState.Disconnected:
Logger.TraceWarning("Database disconnected");
ModifyPluginState(new PluginStateEntry("Database", "Disconnected") { IsWarning = true });
break;
case DatabaseState.Creating:
Logger.TraceInformation("Creating database...");
ModifyPluginState(new PluginStateEntry("Database", "Creating database"));
break;
case DatabaseState.Upgrading:
Logger.TraceInformation("Upgrading database...");
ModifyPluginState(new PluginStateEntry("Database", "Upgrading schema"));
break;
case DatabaseState.Connected:
Logger.TraceInformation("Database connected");
ModifyPluginState(new PluginStateEntry("Database", "Connected"));
break;
case DatabaseState.Error:
Logger.TraceError("Database error state");
ModifyPluginState(new PluginStateEntry("Database",
"Database error") { IsError = true });
break;
}
}DatabaseNotification properties:
-
State- Current database state
Config Tool allows administrators to configure data retention policies for plugins.
Define data retention thresholds that appear in Config Tool:
public override IEnumerable<DatabaseCleanupThreshold> GetDatabaseCleanupThresholds()
{
yield return new DatabaseCleanupThreshold(
name: "EventLog",
title: "Event Log",
defaultIsEnabled: true,
defaultRetentionPeriod: 90);
yield return new DatabaseCleanupThreshold(
name: "AuditTrail",
title: "Audit Trail",
defaultIsEnabled: true,
defaultRetentionPeriod: 365);
}DatabaseCleanupThreshold constructor:
DatabaseCleanupThreshold(string name, string title, bool defaultIsEnabled = true, int defaultRetentionPeriod = 90)-
name- Unique identifier for this threshold (used inDatabaseCleanupcallback) -
title- User-friendly title displayed in Config Tool -
defaultIsEnabled- Whether cleanup is enabled by default -
defaultRetentionPeriod- Default days to retain data (must be > 0 if enabled, must be 0 if disabled)
Config Tool displays these thresholds and allows administrators to:
- Adjust retention periods
- Schedule automatic cleanup
- Manually trigger cleanup
Called when cleanup is triggered (scheduled or manual):
public override void DatabaseCleanup(string name, int retentionPeriod)
{
switch (name)
{
case "EventLog":
CleanupEventLog(retentionPeriod);
break;
case "AuditTrail":
CleanupAuditTrail(retentionPeriod);
break;
}
}
private void CleanupEventLog(int retentionDays)
{
var cutoffDate = DateTime.UtcNow.AddDays(-retentionDays);
using (var connection = m_config.CreateSqlDatabaseConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"
DELETE FROM EventLog
WHERE Timestamp < @CutoffDate";
command.Parameters.AddWithValue("@CutoffDate", cutoffDate);
int deleted = command.ExecuteNonQuery();
Logger.TraceInformation($"Deleted {deleted} old event log entries");
}
}
}Important
- Cleanup runs on a background thread
- Can be long-running without blocking plugin
- Should handle errors gracefully
- Log progress and results
Support database schema versioning with upgrade scripts.
Define incremental schema upgrades:
public override IEnumerable<DatabaseUpgradeItem> GetDatabaseUpgradeItems()
{
// Upgrade from version 1 to version 2
yield return new DatabaseUpgradeItem(
sourceVersion: 1,
targerVersion: 2,
upgradeScript: @"
ALTER TABLE EventLog
ADD [Severity] INT NOT NULL DEFAULT 0;
");
// Upgrade from version 2 to version 3
yield return new DatabaseUpgradeItem(
sourceVersion: 2,
targerVersion: 3,
upgradeScript: @"
CREATE TABLE AuditLog (
Id INT IDENTITY(1,1) PRIMARY KEY,
Timestamp DATETIME2 NOT NULL,
Action NVARCHAR(100),
UserGuid UNIQUEIDENTIFIER
);
");
// Upgrade from version 3 to version 4
yield return new DatabaseUpgradeItem(
sourceVersion: 3,
targerVersion: 4,
upgradeScript: @"
CREATE INDEX IX_AuditLog_Timestamp
ON AuditLog(Timestamp);
");
}DatabaseUpgradeItem constructor:
DatabaseUpgradeItem(int sourceVersion, int targerVersion, string upgradeScript)-
sourceVersion- The version to upgrade from -
targerVersion- The version to upgrade to (note: parameter name contains a typo in the API) -
upgradeScript- SQL script to run for this upgrade
Note
The parameter name targerVersion contains a typo in the SDK API. Use this exact spelling when using named parameters.
How upgrades work:
- Security Center tracks current database version
- Applies upgrades sequentially (1 -> 2 -> 3 -> 4)
- Each upgrade runs in a transaction
- If upgrade fails, database stays at previous version
- Upgrades run during database state transitions and can still be in progress when
OnPluginStart()runs
Version numbering rules:
- Each upgrade specifies source and target versions
- Upgrades must be sequential (no gaps)
- Never change existing upgrade scripts after deployment
Use the DatabaseConfiguration from SetDatabaseInformation(). Wait for
DatabaseState.Connected in OnDatabaseStateChanged() before using the database.
private DatabaseConfiguration m_dbConfig;
public override void SetDatabaseInformation(DatabaseConfiguration config)
{
m_dbConfig = config;
}
public override void OnDatabaseStateChanged(DatabaseNotification notification)
{
if (notification.State == DatabaseState.Connected)
{
InsertEvent("Plugin started", EventType.Information);
}
}
private void InsertEvent(string description, EventType type)
{
using (var connection = m_dbConfig.CreateSqlDatabaseConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = @"
INSERT INTO EventLog (Timestamp, EventType, Description)
VALUES (@Timestamp, @EventType, @Description)";
command.Parameters.AddWithValue("@Timestamp", DateTime.UtcNow);
command.Parameters.AddWithValue("@EventType", type.ToString());
command.Parameters.AddWithValue("@Description", description);
command.ExecuteNonQuery();
}
}
}Use async methods for database access:
private async Task<List<EventRecord>> GetRecentEventsAsync(int count)
{
var events = new List<EventRecord>();
using (var connection = m_dbConfig.CreateSqlDatabaseConnection())
{
await connection.OpenAsync();
using (var command = connection.CreateCommand())
{
command.CommandText = @"
SELECT TOP (@Count) Timestamp, EventType, Description
FROM EventLog
ORDER BY Timestamp DESC";
command.Parameters.AddWithValue("@Count", count);
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
events.Add(new EventRecord
{
Timestamp = reader.GetDateTime(0),
EventType = reader.GetString(1),
Description = reader.GetString(2)
});
}
}
}
}
return events;
}Administrators configure database settings in Config Tool:
Path: System > Roles > PLUGIN-ROLE > Resources > Database
Replace PLUGIN-ROLE with your plugin role name.
Configurable settings:
- SQL Server instance
- Database name (auto-generated, can be changed)
- Connection encryption
- Cleanup thresholds and schedules
Database capabilities:
- Database resources are added to the role when
IPluginDatabaseSupportis implemented - Database encryption support is available with
IPluginDatabaseSupport
- Plugin SDK Overview - Plugin architecture
- Plugin SDK Threading - Threading for database operations
- Plugin SDK Lifecycle - Database initialization timing
- Plugin SDK State Management - Reporting database state
- Logging - Database operation logging
-
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.
-
Workspace SDK
- Workspace SDK Overview Introduction to client-side UI extensions for Security Desk and Config Tool.
- Creating Modules Module lifecycle, registration patterns, and assembly resolution.
- Tasks and Pages Menu items, page content, and navigation.
- Components Dashboard widgets, tiles, maps, credentials, and content builders.
- Tile Extensions Custom tile widgets, views, and properties panels.
- Services Built-in services for dialogs, maps, alarms, badges, and more.
- Contextual Actions Right-click context menu extensions.
- Options Extensions Custom settings pages in application preferences.
- Monitors Multi-monitor support and shared components.
- Commands Command execution, evaluation, and interception.
- Extending Events Adding custom fields to Security Center events.
- Map Extensions Custom map objects, layers, and providers.
- Timeline Providers Custom timeline event sources for video playback.
-
Macro SDK
- Macro SDK Overview How macros work, creating and configuring macro entities, automation, and monitoring.
- Macro SDK Developer Guide Developing macro code with the UserMacro class and Security Center SDK.
-
- Getting Started Setup, authentication, and basic configuration for the Web SDK.
- Referencing Entities Entity discovery, search capabilities, and parameter formats.
- Entity Operations CRUD operations, multi-value fields, and method execution.
- 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.