Skip to content

plugin sdk net8

Andre Lafleur edited this page Feb 16, 2026 · 4 revisions

Building .NET plugins

This guide covers how to build plugins targeting .NET 8 or later for Security Center 5.13 and later.

Version compatibility

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.

Development environment

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_SDK and GSC_SDK_CORE environment variables configured

Visual Studio builds all projects in the solution regardless of target framework. No special configuration is needed to build mixed-framework solutions.

Runtime requirements

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

Plugin components

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.

Choosing a project structure

Three project structures are available for .NET plugins. If your plugin has no ClientModule, reduce the project count by one.

Option 1: One project (multi-target)

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 as Client AND ClientModule
  • net8.0-windows\MyPlugin.dll → register as ServerModule

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 #if directives for framework-specific code

Limitation: All code must compile for both frameworks.

Option 2: Two projects (ServerModule multi-targets)

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 as ClientModule
  • ServerModule\net481\MyPlugin.ServerModule.dll → register as Client
  • ServerModule\net8.0-windows\MyPlugin.ServerModule.dll → register as ServerModule

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.

Option 3: Three projects (no multi-target)

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 #if directives
  • 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).

Summary

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.

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);
#endif

Common 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 ClientStub pattern

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 Plugin with empty bodies
  • Implements IPluginDatabaseSupport if the server plugin uses database storage
  • Contains no business logic

Sharing the PluginDescriptor

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.

Linked files (Add as Link)

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 → AddExisting Item → select file → click dropdown on AddAdd 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

Shared projects

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:

  1. In Visual Studio, add a new project using the Shared Project template
  2. Name it MyPlugin.Shared
  3. Add your PluginDescriptor class 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 #if directives 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

Choosing an approach

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

SDK references by project type

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+).

Code sharing between frameworks

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_GREATER directives 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

Client assembly vs ClientModule

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 Client configuration 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 ClientModule configuration 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.

Supporting multiple Security Center versions

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.

Migrating from .NET Framework to .NET

To convert an existing .NET Framework plugin to .NET:

  1. Choose a project structure from the three options described earlier (or use multi-targeting)

  2. 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
  3. Create the Client assembly

    • Add a new .NET Framework 4.8 class library project
    • Create a stub ClientStub class with [PluginProperty] attribute
    • Link or import the shared PluginDescriptor
    • If your plugin implements IPluginDatabaseSupport, the stub must also implement it
  4. 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
  5. Update registration

    • Change ServerModule path to the .NET DLL
    • Add Client path pointing to the Client assembly
    • Add NetCore = True

Sample projects

The Genetec DAP repository includes sample plugins demonstrating .NET plugin development:

See also

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.
  • Partitions Managing partitions, entity membership, and user access control.
  • Custom Fields Creating, reading, writing, and filtering custom entity fields.
  • Custom Card Formats Managing custom credential card format definitions.
  • Actions Control operations for doors, cameras, macros, and notifications.
  • Events and Alarms Real-time event monitoring, alarm monitoring, and custom events.
  • Incidents Incident management, creation, and attachment handling.
  • Reports Activity reports, entity queries, and historical data retrieval.
  • Performance Guide Optimization tips and best practices for efficient API usage.
  • Reference Entity GUIDs, EntityType enumeration, and EventType enumeration.
  • Under the Hood Technical architecture, query reflection, and SDK internals.
  • Troubleshooting Common error resolution and debugging techniques.

Media Gateway Developer Guide


Web Player Developer Guide

  • 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