-
Notifications
You must be signed in to change notification settings - Fork 6
workspace sdk modules
A workspace module is the entry point for extending Security Desk or Config Tool. Modules are discovered and loaded by the host application, and they register extensions such as tasks, pages, components, and services.
Use a workspace module when you need a client-side entry point that registers UI extensions, shared services, or component builders as the host application starts.
Modules progress through four stages:
- Constructor: Security Center creates your module instance
-
Initialize: The framework calls
Initialize(Workspace)to provide the workspace instance -
Load: The framework calls
Load()where you register all extensions -
Unload: The framework calls
Unload()during application shutdown
The Workspace property is not available in the constructor. Access it only in Load, Unload, or after Initialize completes.
Modules are loaded from plugin installation entries. A deployment file can set the Priority item for a plugin entry; lower values load first. Entries without Priority use the default priority and have no guaranteed order relative to each other. If one assembly contains multiple module classes, do not rely on the order of those classes. Avoid module-to-module load-order dependencies.
If your module throws an exception during Load(), Security Center logs the error and continues loading other modules. Your module will not be added to the workspace, but other modules remain unaffected. The same applies to Unload(): exceptions are caught and logged, allowing other modules to unload normally.
The Load() method is called before the application connects to the Directory server. Do not assume the client is connected when Load() executes. Tasks and pages can work offline by default through the AllowOfflineExecution property on PageDescriptor.
If your module needs to perform actions after connection is established, subscribe to the LoggedOn event:
public override void Load()
{
Workspace.Sdk.LoginManager.LoggedOn += OnLoggedOn;
// Register extensions that work offline
}
private void OnLoggedOn(object sender, LoggedOnEventArgs e)
{
// Perform actions that require connection
}Create a workspace module by inheriting from Genetec.Sdk.Workspace.Modules.Module and overriding the Load and Unload methods:
public class SampleModule : Module
{
public override void Load()
{
// Register extensions here
}
public override void Unload()
{
// Clean up resources here
}
}Your module class must meet these requirements:
-
Public class: The module class must be declared
public. - Default constructor: Security Center requires a public default constructor. If you do not define any constructor, the implicit default constructor satisfies this requirement.
-
Multiple modules per assembly: A single assembly can contain multiple module classes. Security Center discovers and loads all public classes that inherit from
Module.
| Member | Type | Description |
|---|---|---|
Workspace |
Workspace | The workspace instance (available after Initialize) |
UniqueId |
Guid (virtual) | Module's unique identifier (defaults to Type.GUID) |
Load() |
abstract void | Called when module loads; register extensions here |
Unload() |
abstract void | Called when module unloads; clean up here |
Initialize(Workspace) |
void | Called by the framework to set the Workspace property. Do not call or override this method. |
Access the Platform SDK Engine through Workspace.Sdk:
public override void Load()
{
var engine = Workspace.Sdk;
// Subscribe to events (works before connection)
engine.EventReceived += OnEventReceived;
// Check connection before accessing connected-only properties
if (engine.LoginManager.IsConnected)
{
var user = engine.LoggedUser;
}
}All modules share the same Engine instance with the host application. See Platform SDK Overview for Engine operations.
Modules can interact with each other through shared workspace resources:
-
Services: Register a service in one module and retrieve it in another using
Workspace.Services.Get<T>(). Services must implement an interface that extendsIService. -
Components: Access components registered by other modules through
Workspace.Components. -
Modules: Enumerate loaded modules through
Workspace.Modules, though direct module-to-module dependencies are discouraged.
public interface IMyCustomService : IService
{
void DoSomething();
}
public class MyCustomService : IMyCustomService
{
public void Initialize(Workspace workspace) { }
public void DoSomething() { /* ... */ }
}
public class ProducerModule : Module
{
private MyCustomService m_service;
public override void Load()
{
m_service = new MyCustomService();
m_service.Initialize(Workspace);
Workspace.Services.Register(m_service);
}
public override void Unload()
{
if (m_service != null)
{
Workspace.Services.Unregister(m_service);
m_service = null;
}
}
}
public class ConsumerModule : Module
{
public override void Load()
{
var service = Workspace.Services.Get<IMyCustomService>();
service?.DoSomething();
}
public override void Unload()
{
}
}Since loading order is not guaranteed, check for null when retrieving services from other modules. Consider subscribing to Workspace.Initialized to access services after all modules have loaded.
Register extensions in the Load method using the appropriate workspace collection:
public override void Load()
{
// Register a task
var task = new MyTask();
task.Initialize(Workspace);
Workspace.Tasks.Register(task);
// Register a component
var widget = new MyWidgetBuilder();
widget.Initialize(Workspace);
Workspace.Components.Register(widget);
// Register an options extension
var options = new MyOptionsExtension();
options.Initialize(Workspace);
Workspace.Options.Register(options);
}| Extension type | Registration target | Method |
|---|---|---|
| Task | Workspace.Tasks |
Register(Task) |
| Component | Workspace.Components |
Register(Component) |
| OptionsExtension | Workspace.Options |
Register(OptionsExtension) |
| IService | Workspace.Services |
Register(IService) |
| ContextualAction | Workspace.Services.Get<IContextualActionsService>() |
Register(ContextualAction) |
| EventExtender | Workspace.Services.Get<IEventService>() |
RegisterEventExtender(EventExtender) |
| ConfigPage | Workspace.Services.Get<IConfigurationService>() |
Register(ConfigPage) |
Check Workspace.ApplicationType to register extensions only for the appropriate application:
public override void Load()
{
switch (Workspace.ApplicationType)
{
case ApplicationType.SecurityDesk:
RegisterSecurityDeskComponents();
break;
case ApplicationType.ConfigTool:
RegisterConfigToolComponents();
break;
}
}If your module uses third-party libraries beyond the Genetec SDK, you must configure assembly resolution. The SDK assemblies are automatically resolved by Security Center.
This approach configures Security Center to automatically probe your module's directory for dependencies. Set it in the registration XML:
<PluginInstallation>
<Version>1</Version>
<Configuration>
<Item Key="Enabled" Value="True" />
<Item Key="ClientModule" Value="C:\MyModule\MyModule.dll" />
<Item Key="AddFoldersToAssemblyProbe" Value="True" />
</Configuration>
</PluginInstallation>Place all third-party DLLs in the same directory as your module DLL.
For custom loading logic, use the AssemblyResolver sample helper from the DAP samples repository. Copy the class into your project and call its Initialize() method from a static constructor:
public class SampleModule : Module
{
static SampleModule() => AssemblyResolver.Initialize();
public override void Load() { /* ... */ }
public override void Unload() { }
}The static constructor runs before any instance is created, ensuring dependencies resolve correctly.
Use AddFoldersToAssemblyProbe for most scenarios. It requires no code and handles simple dependencies automatically. Use AssemblyResolver when you need custom loading logic, dependencies in multiple locations, or version-specific behavior.
For module registration during development and production deployment, see Deploying plugins and workspace modules.
Release resources in the Unload method:
public override void Unload()
{
// Unsubscribe from events
Workspace.Sdk.EventReceived -= OnEventReceived;
// Dispose loggers
m_logger?.Dispose();
// Release other resources
}The Unload() method is called when the workspace is disposed during normal application shutdown. Do not rely on modules unloading in a specific order. Unload() may not be called if the application crashes, is forcefully terminated, or exits abnormally, so do not make required cleanup depend only on Unload().
- About the Workspace SDK: Workspace SDK architecture and module lifecycle.
- About components: The component registry and registration lifecycle.
- About workspace services: Built-in workspace services and how to consume them.
- About tasks: Adding executable menu items and home tasks.
- Overview
- Connecting to Security Center
- SDK certificates
- Referencing SDK assemblies
- SDK compatibility
- Entities
- Entity cache
- Entity loading, cache, and query options
- Transactions
- Events
- Actions
- Security Desk
- Custom events
- ReportManager
- ReportManager query reference
- Access control raw events
- DownloadAllRelatedData and StrictResults
- Privileges
- Partitions
- About custom fields
- About video
- About cameras
- Enrolling a video unit
- Archiver and auxiliary archiver roles
- Archive transfer
- About access control
- About cardholders and credentials
- About doors, areas, elevators, and access points
- About access rules and schedules
- About access control units and interface modules
- Enrolling an access control unit
- Door templates
- Visitors
- Mobile credentials
- About threat levels
- About alarms
- Maps
- Logging
- Overview
- Certificates
- Lifecycle
- Threading
- State management
- Configuration
- Restricted configuration
- Events
- Queries
- Request manager
- Database
- Entity ownership
- Engine extensions
- Entity mappings
- Server management
- Custom privileges
- Custom entity types
- Resolving non-SDK assemblies
- Deploying plugins
- .NET 8 support
- Overview
- Certificates
- Creating modules
- Tasks
- Pages
- Components
- Tile extensions
- Services
- Contextual actions
- Options extensions
- Configuration pages
- Monitors
- Shared components
- Commands
- Extending events
- Map extensions
- Timeline providers
- Image extractors
- Credential encoders
- Credential readers
- Cardholder fields extractors
- Badge printers
- Content builders
- Dashboard widgets
- Incidents
- Logon providers
- Pinnable content builders
- Custom report pages
- Overview
- Getting started
- MediaPlayer
- VideoSourceFilter
- MediaExporter
- MediaFile
- G64 converters
- FileCryptingManager
- PlaybackSequenceQuerier
- PlaybackStreamReader
- OverlayFactory
- PtzCoordinatesManager
- AudioTransmitter
- AudioRecorder
- AnalogMonitorController
- Camera blocking
- Overview
- Getting started
- Referencing entities
- Entity operations
- About access control in the Web SDK
- About video in the Web SDK
- Users and user groups
- Partitions
- Custom fields
- Custom card formats
- Actions
- Events and alarms
- Incidents
- Reports
- Tasks
- Macros
- Custom entity types
- System endpoints
- Performance guide
- Reference
- Under the hood
- Troubleshooting