-
Notifications
You must be signed in to change notification settings - Fork 3
plugin sdk net8
This guide covers how to build plugins targeting .NET 8 or later for Security Center 5.13 and later.
| Security Center | Supported plugin frameworks |
|---|---|
| 5.12 and earlier | .NET Framework 4.8 only |
| 5.13 | .NET Framework 4.8, .NET 8 |
| 5.14.1 and later | .NET Framework 4.8, .NET 8, .NET 10 |
Note
Security Center 5.12.2 introduced .NET 8 support for Platform SDK applications, but .NET support for role plugins was added in Security Center 5.13.
Building .NET plugins requires:
- Visual Studio 2022 or later (supports both target frameworks in one solution)
- .NET 8 SDK (or later) installed on the development machine
- .NET Framework 4.8 targeting pack for Client and ClientModule projects
-
Security Center SDK 5.13+ with both
GSC_SDKandGSC_SDK_COREenvironment variables configured
Visual Studio builds all projects in the solution regardless of target framework. No special configuration is needed to build mixed-framework solutions.
Modern .NET plugins have different runtime requirements for server and client machines:
Server (runs the plugin):
- Security Center 5.13 or later
- .NET 8 runtime (or later) installed
- The .NET runtime is included with Security Center 5.13+
Client machines (Config Tool, Security Desk):
- .NET Framework 4.8 (included with Windows)
- No .NET runtime required
- Client and ClientModule assemblies run in the existing .NET Framework environment
A plugin has two components:
| Component | Runs in | SDK | .NET support | Purpose |
|---|---|---|---|---|
| ServerModule | Genetec Server (GenetecPlugin.exe) | Plugin SDK | .NET and .NET Framework | Plugin role logic (inherits from Plugin) |
| ClientModule | Config Tool (ConfigTool.exe), Security Desk (SecurityDesk.exe) | Workspace SDK | .NET Framework only | Configuration pages, tasks, tiles (inherits from Module) |
ServerModule contains your plugin's business logic and runs as a role on the server.
ClientModule provides UI in Config Tool and Security Desk using the Workspace SDK. Not all plugins need a ClientModule. Only plugins with custom configuration pages or workspace extensions require one.
For .NET plugins, Config Tool cannot load the ServerModule directly (it's built for .NET, but Config Tool runs on .NET Framework). When you add a plugin role in Config Tool, it loads each registered plugin assembly to find classes with the [PluginProperty] attribute. If your ServerModule targets .NET, Config Tool cannot load it and your plugin will not appear in the list. A Client stub solves this by providing a .NET Framework assembly that Config Tool can load. The stub contains no logic and exists only for discovery.
Three project structures are available for .NET plugins. If your plugin has no ClientModule, reduce the project count by one.
A single project contains both the Module class (Workspace SDK) and the Plugin class (Plugin SDK). Multi-targeting produces two outputs from the same codebase.
<TargetFrameworks>net481;net8.0-windows</TargetFrameworks>Outputs:
-
net481\MyPlugin.dll→ register asClientANDClientModule -
net8.0-windows\MyPlugin.dll→ register asServerModule
Registration:
<PluginInstallation>
<Version>2</Version>
<Configuration>
<Item Key="Client" Value="C:\Plugins\MyPlugin\net481\MyPlugin.dll" />
<Item Key="ClientModule" Value="C:\Plugins\MyPlugin\net481\MyPlugin.dll" />
<Item Key="ServerModule" Value="C:\Plugins\MyPlugin\net8.0-windows\MyPlugin.dll" />
<Item Key="NetCore" Value="True" />
<Item Key="Enabled" Value="True" />
</Configuration>
</PluginInstallation>Note that Client and ClientModule point to the same DLL.
When to use:
- You want the simplest project structure
- Plugin and Module code is mostly framework-agnostic
- You are comfortable using
#ifdirectives for framework-specific code
Limitation: All code must compile for both frameworks.
The ClientModule is in a separate project. The ServerModule multi-targets, and its net481 output serves as the Client.
Projects:
- ClientModule (net481) - Module class (Workspace SDK)
- ServerModule (multi-target) - Plugin class
MyPlugin/
├── MyPlugin.ClientModule/ # .NET Framework 4.8
│ ├── MyPlugin.ClientModule.csproj
│ └── MyPluginModule.cs # Module class
└── MyPlugin.ServerModule/ # Multi-target
├── MyPlugin.ServerModule.csproj
└── MyPlugin.cs # Plugin class
Outputs:
-
ClientModule\net481\MyPlugin.ClientModule.dll→ register asClientModule -
ServerModule\net481\MyPlugin.ServerModule.dll→ register asClient -
ServerModule\net8.0-windows\MyPlugin.ServerModule.dll→ register asServerModule
Registration:
<PluginInstallation>
<Version>2</Version>
<Configuration>
<Item Key="Client" Value="C:\Plugins\MyPlugin\ServerModule\net481\MyPlugin.ServerModule.dll" />
<Item Key="ClientModule" Value="C:\Plugins\MyPlugin\ClientModule\net481\MyPlugin.ClientModule.dll" />
<Item Key="ServerModule" Value="C:\Plugins\MyPlugin\ServerModule\net8.0-windows\MyPlugin.ServerModule.dll" />
<Item Key="NetCore" Value="True" />
<Item Key="Enabled" Value="True" />
</Configuration>
</PluginInstallation>When to use:
- ClientModule is complex enough to warrant a separate project
- Plugin code can compile for both frameworks
Limitation: Plugin code must compile for both frameworks.
Each component is a separate project. The Client is a stub with empty implementations, and the ServerModule targets only .NET.
Projects:
- ClientModule (net481) - Module class (Workspace SDK)
- Client (net481) - Stub Plugin class
- ServerModule (net8.0-windows) - Full Plugin implementation
MyPlugin/
├── MyPlugin.ClientModule/ # .NET Framework 4.8
│ ├── MyPlugin.ClientModule.csproj
│ └── MyPluginModule.cs # Module class
├── MyPlugin.Client/ # .NET Framework 4.8
│ ├── MyPlugin.Client.csproj
│ └── ClientStub.cs # Stub Plugin class
└── MyPlugin.ServerModule/ # .NET only
├── MyPlugin.ServerModule.csproj
└── MyPlugin.cs # Full Plugin implementation
Registration:
<PluginInstallation>
<Version>2</Version>
<Configuration>
<Item Key="Client" Value="C:\Plugins\MyPlugin\MyPlugin.Client.dll" />
<Item Key="ClientModule" Value="C:\Plugins\MyPlugin\MyPlugin.ClientModule.dll" />
<Item Key="ServerModule" Value="C:\Plugins\MyPlugin\MyPlugin.ServerModule.dll" />
<Item Key="NetCore" Value="True" />
<Item Key="Enabled" Value="True" />
</Configuration>
</PluginInstallation>When to use:
- Plugin needs .NET-only APIs without conditional compilation
- You prefer clean code without
#ifdirectives - ServerModule has significant .NET-specific logic
Limitation: More projects to maintain. Client and ServerModule must share the PluginDescriptor via linked files or a shared project (which produces no output and does not count as an additional project).
| Option | Structure | Trade-off |
|---|---|---|
| One project | Multi-target project with Plugin + Module classes | Simplest, all code compiles for both frameworks |
| Two projects | ClientModule + multi-target ServerModule | Separate ClientModule, plugin code compiles for both |
| Three projects | ClientModule + Client stub + ServerModule | Most projects, ServerModule is pure .NET |
Note
Options 1 and 2 use multi-targeting, so plugin code must compile for both .NET Framework and .NET. Use #if NET or #if NETFRAMEWORK directives for framework-specific code. Option 3 allows the ServerModule to target only .NET with no conditional compilation.
Options 1 and 2 require code that compiles for both frameworks. Use preprocessor directives for framework-specific code:
#if NET
// .NET: Use built-in System.Text.Json
var json = JsonSerializer.Serialize(data);
#else
// .NET Framework: Use Newtonsoft.Json
var json = JsonConvert.SerializeObject(data);
#endifCommon symbols:
-
NET- defined for .NET 5+ -
NETFRAMEWORK- defined for .NET Framework -
NET481- defined for .NET Framework 4.8 specifically -
NET8_0- defined for .NET 8 specifically
The Client assembly contains a stub class that exists only so Config Tool can read the [PluginProperty] attribute:
[PluginProperty(typeof(SamplePluginDescriptor))]
public class ClientStub : Plugin
{
protected override void Dispose(bool disposing)
{
// Client stub - no implementation needed
}
protected override void OnQueryReceived(ReportQueryReceivedEventArgs args)
{
// Client stub - no implementation needed
}
}The Plugin base class has abstract methods that must be implemented. The stub provides empty implementations because the stub is only used for discovery and configuration in Config Tool.
If your plugin supports database storage, the stub must also implement IPluginDatabaseSupport:
[PluginProperty(typeof(SamplePluginDescriptor))]
public class ClientStub : Plugin, IPluginDatabaseSupport
{
public DatabaseManager DatabaseManager => new ClientStubDatabaseManager();
protected override void Dispose(bool disposing) { }
protected override void OnQueryReceived(ReportQueryReceivedEventArgs args) { }
}The IPluginDatabaseSupport interface requires a DatabaseManager property. For the Client stub, provide a minimal DatabaseManager implementation:
public class ClientStubDatabaseManager : DatabaseManager
{
public override string GetSpecificCreationScript(string databaseName) => string.Empty;
public override void SetDatabaseInformation(DatabaseConfiguration databaseConfiguration) { }
public override void DatabaseCleanup(string name, int retentionPeriod) { }
public override void OnDatabaseStateChanged(DatabaseNotification notification) { }
}Config Tool loads the Client assembly and checks for IPluginDatabaseSupport to determine whether to display database configuration options. The stub's DatabaseManager is never used at runtime. The actual database logic runs in the ServerModule.
The stub:
- Inherits from
Plugin - Has the
[PluginProperty(typeof(YourPluginDescriptor))]attribute - Implements abstract methods from
Pluginwith empty bodies - Implements
IPluginDatabaseSupportif the server plugin uses database storage - Contains no business logic
The PluginDescriptor class must be identical in both Client and ServerModule. There are two ways to share it:
- Linked files - include a source file from another project without copying it
- Shared projects - a special project type that contains source files compiled into each referencing project
Both approaches compile source files directly into each consuming project. No separate DLL is produced.
A linked file is a reference to a source file that lives in another location. The file stays in its original project folder, but MSBuild compiles it as part of any project that links to it.
How it works:
The <Compile Include="..."> element tells MSBuild to compile a file. The Link attribute controls how the file appears in Solution Explorer. When you build, MSBuild reads the file from its original location and compiles it into the current project.
<ItemGroup>
<Compile Include="..\MyPlugin.ServerModule\MyPluginDescriptor.cs" Link="MyPluginDescriptor.cs" />
</ItemGroup>In Visual Studio: Right-click project → Add → Existing Item → select file → click dropdown on Add → Add as Link
Visual Studio displays linked files with a shortcut arrow icon in Solution Explorer.
When to use linked files:
- Sharing one or two files between projects
- Quick setup with minimal project changes
- File already exists in another project
Considerations:
- The original file must exist at build time or the build fails
- Editing the file in either project modifies the same source
- Files are not physically copied, so they do not appear in the project folder on disk
- Harder to discover when browsing the file system outside Visual Studio
A shared project is a special Visual Studio project type that contains only source files. It produces no DLL. Instead, all files in the shared project are compiled directly into each project that references it.
How it works:
A shared project consists of two files:
-
.shproj- the project file that Visual Studio loads -
.projitems- lists the source files to share
When a project imports the .projitems file, MSBuild includes all listed source files during compilation. Each consuming project compiles its own copy of the code.
Creating a shared project:
- In Visual Studio, add a new project using the Shared Project template
- Name it
MyPlugin.Shared - Add your
PluginDescriptorclass and any shared types
Referencing a shared project:
In both MyPlugin.Client.csproj and MyPlugin.ServerModule.csproj, add:
<Import Project="..\MyPlugin.Shared\MyPlugin.Shared.projitems" Label="Shared" />In Visual Studio: Right-click References (or Dependencies) → Add Shared Project Reference → select the shared project.
When to use shared projects:
- Sharing multiple files between projects
- Files need conditional compilation based on target framework
- Clear organization in Solution Explorer
Considerations:
- Each consuming project compiles the shared code independently
- You can use
#ifdirectives for framework-specific code since files compile in each project's context - Shared projects appear as a separate node in Solution Explorer
- Changes to shared files affect all projects that reference them
| Scenario | Recommendation |
|---|---|
| One or two shared files | Linked files |
| Many shared files | Shared project |
Need #if directives for framework differences |
Shared project |
| Quick setup for existing file | Linked files |
Each project type requires different SDK references:
Client assembly (stub only):
<ItemGroup>
<Reference Include="Genetec.Sdk">
<HintPath>$(GSC_SDK)\Genetec.Sdk.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Genetec.Sdk.Plugin">
<HintPath>$(GSC_SDK)\Genetec.Sdk.Plugin.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>ServerModule (.NET):
<ItemGroup>
<Reference Include="Genetec.Sdk.Plugin">
<HintPath>$(GSC_SDK_CORE)\Genetec.Sdk.Plugin.dll</HintPath>
<Private>False</Private>
</Reference>
<!-- Add other SDK references as needed for your plugin features -->
</ItemGroup>ClientModule (Workspace SDK):
<ItemGroup>
<Reference Include="Genetec.Sdk">
<HintPath>$(GSC_SDK)\Genetec.Sdk.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Genetec.Sdk.Plugin">
<HintPath>$(GSC_SDK)\Genetec.Sdk.Plugin.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Genetec.Sdk.Workspace">
<HintPath>$(GSC_SDK)\Genetec.Sdk.Workspace.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Genetec.Sdk.Controls">
<HintPath>$(GSC_SDK)\Genetec.Sdk.Controls.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>The GSC_SDK environment variable points to the .NET Framework SDK assemblies. The GSC_SDK_CORE environment variable points to the .NET SDK assemblies (available in Security Center 5.13+).
When using multi-targeting or shared projects, the same source files compile for both .NET Framework 4.8 and .NET. Keep these considerations in mind:
API compatibility:
- Shared code must use APIs available in both frameworks
- Use
#if NET8_0_OR_GREATERdirectives for framework-specific code - The compiler will catch incompatible API usage at build time
NuGet packages:
- Packages must support both target frameworks (check the package's supported frameworks)
- Use conditional package references if a package only supports one framework:
<PackageReference Include="SomePackage" Version="1.0.0" Condition="'$(TargetFramework)' == 'net8.0-windows'" />
Separate projects approach:
- ServerModule can use any .NET package without restrictions
- Client and ClientModule are limited to .NET Framework-compatible packages
- No shared code restrictions since projects are independent
These are two distinct concepts:
| Assembly | Purpose | Contains | When Needed |
|---|---|---|---|
| Client | Shows plugin in Config Tool's "Add Plugin" list | Stub Plugin class + PluginDescriptor | Required for all .NET plugins |
| ClientModule | Config Tool UI | Workspace Module class | Only if plugin has configuration UI |
Client assembly
- Allows Config Tool to list your .NET plugin when adding a new plugin role
- Contains a minimal stub Plugin class
- Must target .NET Framework 4.8
- Referenced by the
Clientconfiguration key
ClientModule
- Provides configuration pages and UI in Config Tool or Security Desk
- Contains a class inheriting from
Genetec.Sdk.Workspace.Modules.Module - Must target .NET Framework 4.8
- Referenced by the
ClientModuleconfiguration key - Optional - only needed if your plugin has client-side UI
Note
Config Tool and Security Desk run on .NET Framework 4.8, so workspace modules must target .NET Framework 4.8 to be loaded by these applications.
If your plugin must work with both older Security Center versions (pre-5.13) and newer versions:
Option 1: Ship separate builds
- Build a .NET Framework version for older Security Center
- Build a .NET version for Security Center 5.13+
- Distribute the appropriate version based on the target environment
Option 2: Use .NET Framework only
- Target .NET Framework 4.8 for maximum compatibility
- Works on all Security Center versions
- Does not require Client/ServerModule separation
Modern .NET plugins cannot run on Security Center versions prior to 5.13. There is no single binary that works on both old and new versions.
To convert an existing .NET Framework plugin to .NET:
-
Choose a project structure from the three options described earlier (or use multi-targeting)
-
Share your PluginDescriptor between Client and ServerModule
- Option A: Use "Add as Link" to link the file from one project to the other
- Option B: Create a shared project and import it into both projects
-
Create the Client assembly
- Add a new .NET Framework 4.8 class library project
- Create a stub
ClientStubclass with[PluginProperty]attribute - Link or import the shared PluginDescriptor
- If your plugin implements
IPluginDatabaseSupport, the stub must also implement it
-
Move your plugin logic to the ServerModule
- Create a new .NET class library project
- Move your existing plugin code
- Update SDK references to use
$(GSC_SDK_CORE) - Link or import the shared PluginDescriptor
-
Update registration
- Change
ServerModulepath to the .NET DLL - Add
Clientpath pointing to the Client assembly - Add
NetCore = True
- Change
The Genetec DAP repository includes sample plugins demonstrating .NET plugin development:
- CustomActionSample - Custom actions with Client stub
- CustomReportSample - Custom reports with ClientModule
-
PluginDatabaseSample - Database support with
IPluginDatabaseSupport - BasicPluginTemplate - Minimal plugin template
-
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
- Overview Introduction to plugin architecture and capabilities.
- Certificates SDK certificate requirements for plugin roles.
- Lifecycle Initialization and disposal patterns.
- Threading Threading model, QueueUpdate, and async patterns.
- State Management Reporting plugin health and diagnostics.
- Configuration Configuration storage and monitoring.
- Restricted Configuration Secure credential storage and admin-only configuration.
- Events Event subscription and handling.
- Queries Query processing and response handling.
- Request Manager Request/response communication with clients.
- Database Database integration and schema management.
- Entity Ownership Understanding plugin-owned entities, running state management, and ownership release.
- Entity Mappings Using EntityMappings for plugin-specific configuration and external system integration.
- Server Management High availability and server failover.
- Custom Privileges Defining and enforcing custom privileges.
- Custom Entity Types Defining and managing plugin-specific entity types.
- Resolving Non-SDK Assemblies Handling third-party dependencies in plugins and workspace modules.
- Deploying Plugins Registering and deploying plugins and workspace modules.
- .NET 8 Support Building plugins with .NET 8 and .NET Standard compatibility.
-
Workspace SDK
- Overview Introduction to client-side UI extensions for Security Desk and Config Tool.
- Certificates SDK certificate requirements for workspace modules.
- Creating Modules Module lifecycle, registration patterns, and assembly resolution.
- Tasks Executable actions, home page entries, and programmatic invocation.
- Pages Page content, lifecycle, descriptors, 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.
- Configuration Pages Entity configuration pages for Config Tool.
- Monitors Multi-monitor support and shared components.
- Shared Components Using monitor and workspace shared UI 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.
- Image Extractors Custom image sources for cardholder photos and custom fields.
- Credential Encoders Encoding credentials with custom encoder components.
- Cardholder Fields Extractors Importing cardholder data from external sources.
- Content Builders Building and customizing tile content in Security Desk.
-
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.
-
- 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.
- 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.