-
Notifications
You must be signed in to change notification settings - Fork 4
macro sdk developer guide
This guide covers developing macro code using the Security Center SDK. For information on creating and configuring macro entities, execution contexts, automation, and monitoring, see the Macro SDK Overview.
Macros consist of two parts: the macro entity and your C# class.
The macro entity is a Security Center entity stored in the Directory (like cameras, doors, or users). It contains:
- The C# source code
- Configuration (name, description, partitions)
- Default execution context (parameter values)
- Permissions and access control
Macro entities can be created in:
- Config Tool: Manually through the graphical interface
-
Platform SDK: Programmatically using
Engine.CreateEntity(EntityType.Macro)
The UserMacro class is the C# code you write that inherits from Genetec.Sdk.Scripting.UserMacro. It contains:
- The
Execute()method with your logic - Parameter properties (input values)
- SDK access for interacting with Security Center
Key characteristics:
- Written in C#
- Run server-side on the Security Center server (not on client machines)
- Have full access to the Platform SDK
- Can respond to events, process entities, and automate workflows
- One macro entity can spawn multiple
UserMacroinstances (unlessSingleInstance = true)
Important
Macros execute on the Security Center server, not on the client machine running Config Tool or Security Desk. This means:
- Macros have access to server resources
- File paths in macros refer to the server's file system, not the client's
- The SDK context is pre-authenticated by the macro runtime. All SDK calls run under a Security Center service context rather than the interactive user who triggered the macro.
- Macros continue running even if the client disconnects
You can create macro entities programmatically using the Platform SDK. This is useful for automated macro deployment, testing, or management scenarios.
using Genetec.Sdk;
using Genetec.Sdk.Entities;
using Genetec.Sdk.Scripting.Compiler;
using Genetec.Sdk.Scripting.Compiler.CodeBuilder;
// Create a macro source code builder
IMacroSourceCodeBuilder builder = CodeBuilderFactory.Create();
builder.AddProperty(typeof(Guid), "CameraEntity");
builder.AddProperty(typeof(string), "Message");
builder.SetClassAttributeParameters(singleInstance: true);
builder.SetExecuteMethodContent(@"
MacroLogger.TraceInformation($""Camera: {CameraEntity}, Message: {Message}"");
");
string macroSourceCode = builder.Build();
// Create the macro entity within a transaction
Macro macro = await engine.TransactionManager.ExecuteTransactionAsync(() =>
{
var newMacro = (Macro)engine.CreateEntity("Camera Alert Macro", EntityType.Macro);
newMacro.SetSourceCode(macroSourceCode);
newMacro.Description = "Logs camera alert messages";
return newMacro;
});
// Execute the macro
var parameters = macro.DefaultParameters;
parameters["CameraEntity"].Value = someCameraGuid;
parameters["Message"].Value = "Motion detected";
Guid instanceId = macro.Execute(parameters);For more details on working with macro entities, see MacroSample.cs in the Platform SDK samples.
All macros inherit from Genetec.Sdk.Scripting.UserMacro, which provides access to Security Center and the macro runtime.
Understanding the complete lifecycle of a macro execution:
1. User/System triggers macro execution
↓
2. Macro Agent creates instance via parameterless constructor
⚠️ Sdk, MacroLogger, parameters are NULL here
↓
3. Framework initializes base class properties
• Sets Sdk, MacroLogger, InstanceGuid, MacroGuid, etc.
↓
4. Framework sets macro parameter properties
• Your public properties are populated
↓
5. Framework raises Started event
↓
6. Framework calls your Execute() method
• All properties are now initialized and ready
• Your macro logic runs here
↓
7. Execute() completes or throws exception
↓
┌─────────────────┴─────────────────┐
│ │
▼ Normal completion ▼ Exception thrown
│ │
│ If KeepRunningAfterExecute: │ Macro marked as failed
│ - false: Go to cleanup │ Exception logged
│ - true: Wait for Exit() call │
│ │
└─────────────────┬─────────────────┘
↓
8. Framework calls CleanUp() (ALWAYS)
• Guaranteed execution even on exception
• Active transactions are auto-rolled back
• Unsubscribe events and dispose resources
↓
9. Framework raises Completed or Aborted event
↓
10. Framework disposes macro instance
Key Points:
- The constructor runs before any initialization
-
Execute()is where your main logic lives -
CleanUp()always executes, even on exceptions - Events let you track lifecycle stages
- Long-running macros need
KeepRunningAfterExecute = trueandExit()
The UserMacro base class provides these key properties:
| Property | Type | Description |
|---|---|---|
Sdk |
Engine |
Access to the Platform SDK Engine for interacting with Security Center |
MacroLogger |
Logger |
Logger instance for tracing macro execution |
MacroAbortToken |
CancellationToken |
Token signaled when the macro should stop |
InstanceGuid |
Guid |
Unique identifier for this execution instance |
MacroGuid |
Guid |
The macro entity GUID |
InstigatorGuid |
Guid |
GUID of the user or application that triggered execution |
TriggeringEvent |
Event |
The event that triggered execution (if applicable) |
UtcStartTimestamp |
DateTime |
When the macro started (UTC) |
You can override these properties in your macro class to customize behavior:
| Property | Type | Default Value | Description |
|---|---|---|---|
LoggerName |
string |
InstanceGuid.ToString("n") |
Name used for the logger instance |
TracePrefix |
string |
"Macro {MacroGuid} - " |
Prefix added to trace messages |
[MacroParameters(SingleInstance = true)]
public class CustomLogMacro : UserMacro
{
protected override string LoggerName
{
get { return "MyCustomLogger"; }
}
protected override string TracePrefix
{
get { return string.Format("[{0}] ", MacroGuid); }
}
public override void Execute()
{
MacroLogger.TraceInformation("This uses custom logger name and prefix");
}
protected override void CleanUp()
{
}
}Your macro class can optionally define a parameterless constructor.
Important
The framework calls the constructor before any macro properties are initialized. Sdk, MacroLogger, InstanceGuid, MacroGuid, and all other base class properties are NULL or empty in the constructor.
- Macro parameters (your public properties) are not yet set
- You should not perform any work in the constructor
- Keep the constructor empty or use it only for initializing your own private fields
[MacroParameters(SingleInstance = true)]
public class MyMacro : UserMacro
{
public Guid CameraGuid { get; set; }
private readonly List<string> m_myData = new List<string>(); // OK - initializing your own fields
public MyMacro()
{
// DON'T do this - Sdk is null here!
// var camera = Sdk.GetEntity(CameraGuid); // WILL FAIL!
// DON'T do this - MacroLogger is null here!
// MacroLogger.TraceInformation("Starting"); // WILL FAIL!
// OK - initializing your own state
m_myData.Add("initialized");
}
public override void Execute()
{
// NOW everything is initialized - do your work here
MacroLogger.TraceInformation("Macro started");
var camera = Sdk.GetEntity(CameraGuid);
}
protected override void CleanUp()
{
}
}Initialization order:
- Constructor called (nothing initialized yet)
- Macro framework sets
Sdk,MacroLogger,InstanceGuid, etc. - Macro framework sets your parameter properties
- Framework calls
Execute()(everything is now initialized)
A macro file can contain multiple classes to organize complex logic. However, the macro runtime requires exactly one entry point class.
Requirements:
- Exactly one class must inherit from
UserMacro(orUserMacroWithSetup) - Additional classes must be regular C# classes that do not inherit from
UserMacro - Helper classes can be static classes, utility classes, data models, or extension methods
Tip
Use a unique, descriptive class name for your macro entry point class (e.g., SendEmailOnAlarmMacro instead of the default myMacro). While the system supports multiple macros with the same class name (each compiles to a separate assembly), unique names make logs, stack traces, and debugging much clearer.
using Genetec.Sdk.Scripting;
// Helper class - does NOT inherit from UserMacro
public class MessageFormatter
{
public string Format(string name, int count)
{
return string.Format("{0}: {1} items", name, count);
}
}
// Entry point - the ONLY class that inherits from UserMacro
public class MyMacro : UserMacro
{
private MessageFormatter _formatter = new MessageFormatter();
public override void Execute()
{
string message = _formatter.Format("Result", 42);
MacroLogger.TraceInformation(message);
}
protected override void CleanUp()
{
}
}Important
If multiple classes inherit from UserMacro, the macro will fail to execute because the runtime cannot determine which class is the entry point.
The entry point for your macro logic. You must override this abstract method. The framework calls it when the macro starts.
public override void Execute()
{
MacroLogger.TraceInformation("Macro started");
// Your automation logic here
}Called when the macro completes or is aborted. This is a virtual method with an empty default implementation, so overriding it is optional. Override this method when you need to release resources, unsubscribe from events, or perform cleanup operations.
protected override void CleanUp()
{
// Unsubscribe from events
Sdk.AlarmTriggered -= OnAlarmTriggered;
// Dispose resources
MacroLogger.TraceInformation("Cleanup completed");
}Important
Always clean up in CleanUp(), not in Execute(). The runtime guarantees CleanUp() will be called even if Execute() throws an exception.
Configure macro behavior with the [MacroParameters] attribute applied to your macro class.
[MacroParameters(
SingleInstance = true,
KeepRunningAfterExecute = true,
Run64Bit = false,
RequestAdminRights = false,
MacroGroup = "MyGroup")]
public class MyMacro : UserMacro
{
public override void Execute()
{
// Your macro logic
}
protected override void CleanUp()
{
}
}| Property | Type | Default | Description |
|---|---|---|---|
SingleInstance |
bool |
false |
Only one instance of this macro can run at a time |
KeepRunningAfterExecute |
bool |
false |
Macro stays active after Execute() returns |
Run64Bit |
bool |
false |
Force macro to run in 64-bit process |
RequestAdminRights |
bool |
false |
Request elevated Windows privileges |
MacroGroup |
string |
null |
Group macros in same application domain |
Type: bool (default: false)
When true, only one instance of this specific macro can run at a time. If another execution request is made while an instance is already running, the new request will be ignored.
Important
This applies per-macro, not globally. Other macros can still run concurrently.
Use when:
- The macro modifies shared state or resources specific to its purpose
- Multiple instances of the same macro would conflict with each other
- The macro performs resource-intensive operations that shouldn't run concurrently
[MacroParameters(SingleInstance = true)]
public class ConfigUpdateMacro : UserMacro
{
// Only one instance of ConfigUpdateMacro at a time
// Other macros can still run
public override void Execute()
{
// Your logic
}
protected override void CleanUp()
{
}
}Type: bool (default: false)
When true, the macro continues running after the Execute() method completes. This is essential for event-driven macros that need to respond to ongoing system events.
- The macro stays active until manually aborted by a user or until it calls
Exit() - Typically used with event subscriptions in the
Execute()method - The macro waits indefinitely after
Execute()returns - Call
Exit()from within the macro to terminate gracefully
When false (default), the macro terminates automatically when Execute() returns.
[MacroParameters(KeepRunningAfterExecute = true, SingleInstance = true)]
public class AlarmMonitorMacro : UserMacro
{
public override void Execute()
{
// Subscribe to events
Sdk.AlarmTriggered += OnAlarm;
// Execute() returns but macro keeps running
// waiting for alarm events
}
void OnAlarm(object sender, AlarmTriggeredEventArgs e)
{
// Handle alarm
if (MacroAbortToken.IsCancellationRequested)
{
Exit(); // Cleanly terminate the macro
}
}
protected override void CleanUp()
{
Sdk.AlarmTriggered -= OnAlarm;
}
}Type: bool (default: false)
Controls whether the macro runs in a 64-bit or 32-bit process.
- When
true, the macro runs in a 64-bit process - When
false(default), the macro runs in a 32-bit process
Use Run64Bit = true when:
- The macro needs more than 2GB of memory
- The macro uses 64-bit native libraries
- The macro performs memory-intensive operations (large datasets, image processing, etc.)
Note
Most macros don't need this. Keep the default unless you have specific requirements. The Run64Bit parameter availability depends on your Security Center version.
[MacroParameters(Run64Bit = true)]
public class LargeDataProcessingMacro : UserMacro
{
// Processes large amounts of data
public override void Execute()
{
// Your logic
}
protected override void CleanUp()
{
}
}Type: bool (default: false)
When true, the macro requests elevated privileges to run with administrative rights.
- Required when the macro needs to perform privileged operations
- The macro process will run with elevated permissions
Use when:
- The macro needs to access protected system resources
- The macro performs operations that require administrative privileges
- The macro interacts with Windows services or system-level components
Caution
Only use this when absolutely necessary. Running with admin rights increases security risks.
[MacroParameters(RequestAdminRights = true)]
public class SystemConfigMacro : UserMacro
{
// Modifies system-level configuration
public override void Execute()
{
// Your logic
}
protected override void CleanUp()
{
}
}Type: string (default: empty/null)
Defines which application domain (AppDomain) the macro runs in. All macros with the same MacroGroup value share the same AppDomain and SDK Engine instance.
- By default (null or empty), all macros run in the same AppDomain
- Each AppDomain has a single shared SDK Engine instance
- Macros in the same group share resources but are isolated from other groups
- Different groups run in separate processes, providing isolation
Use when:
- You need to isolate macros from each other
- Different macros have conflicting dependencies or assemblies
- You want to prevent one macro's failures from affecting another
- You need to control resource allocation per group
[MacroParameters(MacroGroup = "VideoProcessing")]
public class VideoAnalysisMacro : UserMacro
{
// Runs in "VideoProcessing" AppDomain with other video macros
public override void Execute()
{
// Your logic
}
protected override void CleanUp()
{
}
}
[MacroParameters(MacroGroup = "AccessControl")]
public class DoorControlMacro : UserMacro
{
// Runs in "AccessControl" AppDomain, isolated from video macros
public override void Execute()
{
// Your logic
}
protected override void CleanUp()
{
}
}Tip
Creating separate AppDomains has overhead. Group related macros together when possible to minimize resource usage.
Macros can accept typed parameters that are set before execution. Parameters are defined as public auto-implemented properties in your macro class.
Parameters are automatically discovered by the compiler through reflection. Any public property with a supported type becomes a parameter.
[MacroParameters(SingleInstance = true)]
public class ParameterizedMacro : UserMacro
{
// These properties automatically become macro parameters
public Guid CameraGuid { get; set; }
public bool IsEnabled { get; set; }
public string Message { get; set; }
public int RetryCount { get; set; }
public DateTime StartTime { get; set; }
public double Threshold { get; set; }
public override void Execute()
{
if (CameraGuid == Guid.Empty)
{
MacroLogger.TraceWarning("CameraGuid not set");
return;
}
MacroLogger.TraceInformation(string.Format("Processing camera: {0}", CameraGuid));
MacroLogger.TraceInformation(string.Format("Message: {0}", Message));
MacroLogger.TraceInformation(string.Format("RetryCount: {0}", RetryCount));
}
protected override void CleanUp()
{
}
}Only these types are supported as macro parameters:
| Type | Default Value | Description |
|---|---|---|
int |
0 |
32-bit signed integer |
Guid |
Guid.Empty |
Globally unique identifier |
bool |
false |
Boolean value |
string |
"" (empty) |
Text string |
DateTime |
DateTime.MinValue |
Date and time |
double |
0.0 |
Double-precision floating point |
Important
Using any other type will cause the property to be ignored as a parameter. Notably, uint, long, and float are not supported.
For a property to be recognized as a macro parameter, it must meet ALL of these conditions:
- Must be a property (not a field)
-
Must have a public setter -
{ get; set; }with public accessibility - Must be writable - Read-only properties are ignored
- Must have a supported type - One of the types listed above
-
Must not conflict with base class property names - Read-only base class properties like
Sdk,MacroLogger,InstanceGuid,MacroGuid, etc. will cause compilation errors if redeclared. Additionally, avoid using the property namePermissionSet, which is reserved by the base class (though it won't cause compilation errors, it may be ignored during parameter discovery)
// ✅ VALID parameters
public int Count { get; set; } // Public auto-property
public string Name { get; set; } // Public auto-property
// ❌ INVALID - will be IGNORED
private int privateCount { get; set; } // Private - ignored
public int ReadOnlyCount { get; } // No setter - ignored
public int ReadOnlyCount { get; private set; } // Private setter - ignored
public TimeSpan Duration { get; set; } // Unsupported type - ignored
public int myField; // Field, not property - ignoredUse MacroLogger for all macro logging. Do not use Console.WriteLine().
public override void Execute()
{
MacroLogger.TraceInformation("Macro started");
MacroLogger.TraceDebug("Debug information");
MacroLogger.TraceWarning("Warning message");
try
{
// Do work
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Operation failed");
throw; // Re-throw to mark macro as failed
}
}Log Levels:
-
TraceInformation()- General information -
TraceDebug()- Detailed debugging information -
TraceWarning()- Warning messages -
TraceError()- Error messages (with optional exception)
The UserMacro base class provides a simpler Trace(string) protected method that automatically prepends the TracePrefix:
public override void Execute()
{
Trace("Starting processing"); // Automatically includes TracePrefix
// Equivalent to:
// MacroLogger.TraceInformation(TracePrefix + "Starting processing");
}This is convenient for quick logging, but MacroLogger methods offer more control with different log levels and exception handling.
The Sdk property gives you full access to the Platform SDK Engine. The macro framework automatically handles authentication using credentials provided by the Directory server, so you don't need to call engine.LogOn() or manage connections.
Warning
Never instantiate your own Engine class, call LogOn()/LogOff() methods, or dispose the Sdk or MacroLogger instances. The macro runtime manages these shared resources across all macros in the application domain.
public Guid CameraGuid { get; set; }
public Guid AlarmGuid { get; set; }
public override void Execute()
{
// Get entity by GUID
var camera = Sdk.GetEntity(CameraGuid);
// Subscribe to events
Sdk.AlarmTriggered += OnAlarmTriggered;
Sdk.EntityAdded += OnEntityAdded;
// Use managers
Sdk.AlarmManager.AcknowledgeAlarm(InstanceGuid, AlarmGuid, AcknowledgementType.Ack);
// Run queries
var query = (EntityConfigurationQuery)Sdk.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
// Transactions (synchronous version)
Sdk.TransactionManager.ExecuteTransaction(() =>
{
// Modify entities atomically
});
// Or use async version with helper method (see Async Operations section)
ExecuteAsync().GetAwaiter().GetResult();
}
private async Task ExecuteAsync()
{
await Sdk.TransactionManager.ExecuteTransactionAsync(() =>
{
// Modify entities atomically
});
}For more details on working with the Platform SDK, see the Platform SDK overview.
The Execute() method is synchronous, but you can use async/await internally:
public Guid TargetGuid { get; set; }
public override void Execute()
{
ExecuteAsync().GetAwaiter().GetResult();
}
private async Task ExecuteAsync()
{
var entity = Sdk.GetEntity(TargetGuid);
await ProcessEntityAsync(entity);
}
private async Task ProcessEntityAsync(Entity entity)
{
// Async processing logic
await Task.Delay(100); // Example async operation
MacroLogger.TraceInformation(string.Format("Processed: {0}", entity.Name));
}Check MacroAbortToken for long-running operations:
public override void Execute()
{
for (int i = 0; i < 1000; i++)
{
if (MacroAbortToken.IsCancellationRequested)
{
MacroLogger.TraceInformation("Abort requested, stopping");
return;
}
ProcessItem(i);
}
}For macros with KeepRunningAfterExecute = true, use the Exit() method to cleanly terminate the macro from within your code:
[MacroParameters(KeepRunningAfterExecute = true, SingleInstance = true)]
public class MonitoringMacro : UserMacro
{
private int eventCount = 0;
public override void Execute()
{
Sdk.AlarmTriggered += OnAlarm;
// Execute() returns but macro keeps running
}
void OnAlarm(object sender, AlarmTriggeredEventArgs e)
{
eventCount++;
MacroLogger.TraceInformation(string.Format("Alarm #{0}", eventCount));
// Stop after processing 100 alarms
if (eventCount >= 100)
{
MacroLogger.TraceInformation("Limit reached, exiting");
Exit(); // Cleanly stops the macro
}
}
protected override void CleanUp()
{
Sdk.AlarmTriggered -= OnAlarm;
}
}Important
-
Exit()can only be called in macros withKeepRunningAfterExecute = true
- Calling it on other macros throws
InvalidOperationException - After calling
Exit(),CleanUp()will be called automatically - This is the proper way to stop a long-running macro from within (rather than external abort)
The UserMacro class provides three instance-level events that you can subscribe to within your macro code:
[MacroParameters(SingleInstance = true)]
public class EventAwareMacro : UserMacro
{
public EventAwareMacro()
{
// Subscribe to macro lifecycle events
Started += OnMacroStarted;
Completed += OnMacroCompleted;
Aborted += OnMacroAborted;
}
private void OnMacroStarted(object sender, MacroEventArgs e)
{
// Called when this macro instance starts
MacroLogger.TraceInformation(string.Format("Macro {0} started, instance {1}", e.MacroGuid, e.InstanceGuid));
}
private void OnMacroCompleted(object sender, MacroEventArgs e)
{
// Called when this macro instance completes successfully
MacroLogger.TraceInformation("Macro completed successfully");
}
private void OnMacroAborted(object sender, MacroEventArgs e)
{
// Called when this macro instance is aborted
if (e.RuntimeException != null)
{
MacroLogger.TraceError(e.RuntimeException, "Macro aborted due to exception");
}
else
{
MacroLogger.TraceWarning("Macro was aborted");
}
}
public override void Execute()
{
// Your macro logic
}
protected override void CleanUp()
{
// Unsubscribe from events
Started -= OnMacroStarted;
Completed -= OnMacroCompleted;
Aborted -= OnMacroAborted;
}
}Events:
-
Started- Raised when the macro execution begins -
Completed- Raised when the macro completes normally -
Aborted- Raised when the macro is aborted or fails
MacroEventArgs Properties:
-
InstanceGuid- The unique execution instance ID -
MacroGuid- The macro entity GUID -
RuntimeException- The exception that caused failure (if any)
Note
These are instance events for this specific macro execution. They're different from the static events on the Macro entity class used for external monitoring.
Understanding how exceptions affect macro execution:
When Execute() completes without throwing an exception:
- If
KeepRunningAfterExecute = false: Macro stops and is marked as completed - If
KeepRunningAfterExecute = true: Macro continues running until you callExit()or Security Center aborts it - Framework calls
CleanUp() - Framework raises the
Completedevent
When Execute() throws an exception:
- The exception is caught by the macro framework
- The macro is marked as failed
- The exception is logged via
MacroLogger.TraceError() -
CleanUp()is still called (guaranteed) - Framework raises the
Abortedevent withRuntimeExceptionset
public override void Execute()
{
try
{
// Your logic
if (somethingWentWrong)
{
throw new InvalidOperationException("Something went wrong");
}
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Failed to process");
throw; // Re-throw to mark macro as failed
}
// CleanUp() is guaranteed to be called even if exception is thrown
}ThreadAbortException is treated specially - it's considered an abort rather than a failure. This happens when:
- The macro is manually aborted by a user
- The Security Center service is shutting down
If a transaction is active when the macro ends (normally or abnormally), it's automatically rolled back in CleanUp().
Important
Since Execute() is void (not async), you must use the sync-over-async pattern to call async transaction methods:
public override void Execute()
{
// Pattern 1: Using GetAwaiter().GetResult() for async methods
ExecuteAsync().GetAwaiter().GetResult();
}
private async Task ExecuteAsync()
{
await Sdk.TransactionManager.ExecuteTransactionAsync(() =>
{
// Modify entities
var cardholder = (Cardholder)Sdk.CreateEntity("John Doe", EntityType.Cardholder);
cardholder.FirstName = "John";
if (someError)
{
// Exception here rolls back the transaction automatically
throw new InvalidOperationException("Cannot proceed");
}
});
// Transaction is committed when ExecuteTransactionAsync completes successfully
}
protected override void CleanUp()
{
// If a transaction is still active here (unusual case), it will be rolled back automatically
// This is a safety net - you should normally commit or rollback explicitly
}Alternative Pattern: Use synchronous ExecuteTransaction() directly:
public override void Execute()
{
Sdk.TransactionManager.ExecuteTransaction(() =>
{
// Modify entities
var cardholder = (Cardholder)Sdk.CreateEntity("John Doe", EntityType.Cardholder);
cardholder.FirstName = "John";
if (someError)
{
throw new InvalidOperationException("Cannot proceed");
}
});
// Transaction is committed when ExecuteTransaction completes successfully
}Automatic Rollback Scenarios:
-
Exception during transaction: Transaction is automatically rolled back by
ExecuteTransaction()orExecuteTransactionAsync() -
Uncommitted transaction at macro end: If you manually create a transaction but don't commit it before the macro ends,
CleanUp()automatically rolls it back -
Manual transaction with exception: If using
CreateTransaction()/CommitTransaction()and an exception occurs, you must handle rollback explicitly (unless using therollBackOnFailure: trueparameter)
Best Practice: Always complete transactions explicitly using ExecuteTransaction() / ExecuteTransactionAsync() or by calling CommitTransaction() after CreateTransaction(). The automatic rollback in CleanUp() is a safety mechanism, not the primary way to manage transactions.
The static property Macro.InExecutionEnvironment indicates whether Security Center is executing the macro or just inspecting it:
using Genetec.Sdk.Scripting;
using Genetec.Sdk.Scripting.Interfaces;
public class DesignAwareMacro : UserMacro
{
public DesignAwareMacro()
{
// Avoid expensive initialization during design-time
if (!Genetec.Sdk.Scripting.Interfaces.Macro.InExecutionEnvironment)
{
return; // Being instantiated for inspection only
}
// Safe to perform initialization that has side effects
}
public override void Execute()
{
// This is only called during actual execution
// InExecutionEnvironment is always true here
}
protected override void CleanUp()
{
}
}When is InExecutionEnvironment false?
- When the Macro Compiler inspects your macro to discover parameters
- During compilation and validation
When is InExecutionEnvironment true?
- During actual macro execution
- Inside
Execute()andCleanUp()methods
Use this to:
- Avoid expensive initialization during design-time
- Prevent side effects when Config Tool inspects the macro
- Skip resource allocation that's only needed at runtime
Important
Properties like Sdk, MacroLogger, and parameters are NULL when InExecutionEnvironment is false. Only use this flag in the constructor to control initialization logic.
Important
Macros run server-side on the Security Center server, not on the client machine. This means:
- Visual Studio must be running on the server for local debugging
- Alternatively, use Visual Studio Remote Debugging from your development machine to connect to the server
- You cannot debug macros by running Visual Studio only on the client without remote debugging configured
The most effective way to debug your macro code is to use System.Diagnostics.Debugger.Launch() to attach a debugger when the macro executes:
using System.Diagnostics;
using Genetec.Sdk.Scripting;
using Genetec.Sdk.Scripting.Interfaces.Attributes;
[MacroParameters(SingleInstance = true)]
public class MyDebuggableMacro : UserMacro
{
public override void Execute()
{
// Launch debugger at the start of execution
if (!Debugger.IsAttached)
{
Debugger.Launch();
}
// Your macro logic here - you can now set breakpoints
MacroLogger.TraceInformation("Starting macro execution");
// ... rest of your code
}
protected override void CleanUp()
{
}
}How it works:
- Add
Debugger.Launch()at the beginning of yourExecute()method - Run the macro from Config Tool (manually or via Event-to-Action)
- When the dialog appears, select your running Visual Studio instance
- Visual Studio will attach and break at the
Debugger.Launch()call - Set breakpoints in your code and step through execution
- Debug normally using Visual Studio's debugging tools
Tips:
- Use
if (!Debugger.IsAttached)to avoid re-launching if already debugging - Remove or comment out
Debugger.Launch()before deploying to production - You can also add it conditionally based on a macro parameter:
public bool EnableDebugging { get; set; }
public override void Execute()
{
if (EnableDebugging && !Debugger.IsAttached)
{
Debugger.Launch();
}
// Your code
}If you prefer not to modify your macro code, you can manually attach Visual Studio to the macro process:
Steps:
- On the Security Center server, open Visual Studio
- Go to Debug > Attach to Process... (or press
Ctrl+Alt+P) - Look for one of these processes:
- MacroAgent.exe - The main macro execution service
- GenetecMacroSubprocess32.exe - 32-bit macro subprocess
-
GenetecMacroSubprocess64.exe - 64-bit macro subprocess (if using
Run64Bit = true)
- Select the appropriate process and click Attach
- Set breakpoints in your macro code
- Trigger the macro execution from Config Tool
Tips:
- If your macro uses
Run64Bit = false(default), attach to GenetecMacroSubprocess32.exe - If your macro uses
Run64Bit = true, attach to GenetecMacroSubprocess64.exe - You may need to attach before the macro runs, or ensure it's a long-running macro
- For first-time execution, the subprocess may not exist until the macro starts
- Consider using
Debugger.Launch()for easier one-time debugging, and manual attach for production troubleshooting
Debugging Managed Code:
When attaching, ensure you select Managed (.NET Framework) as the code type in the "Attach to Process" dialog.
Remote Debugging:
If Visual Studio is running on your development machine (not the server), you can use Visual Studio Remote Debugging:
- Install Remote Tools for Visual Studio on the Security Center server
- Run Remote Debugger (msvsmon.exe) on the server
- In Visual Studio on your dev machine, use Debug > Attach to Process...
- Set Connection type to Remote (no authentication) or Remote (Windows Authentication)
- Enter the server name or IP address
- Select the macro process and attach
This allows you to debug from your development workstation without running Visual Studio on the server.
For quick state inspection without a full debugger, you can send messages to Config Tool:
public override void Execute()
{
// Send diagnostic messages visible in Config Tool
Sdk.ActionManager.SendMessage(
SdkGuids.Administrator,
$"Processing {entityCount} entities"
);
// Continue with your logic
}This is useful for:
- Checking if the macro is executing
- Viewing variable values without stopping execution
- Confirming logic flow in production environments
Note
Use this sparingly as it can create notification noise in Config Tool.
Change the default macro class name from myMacro to something descriptive and unique. Log messages show the class name, making it easier to identify which macro is executing. Stack traces and error messages become clearer when class names are unique. While the system supports multiple macros with identical class names (each compiles to a separate assembly), unique names improve maintainability.
Poor example - default name, not descriptive:
public class myMacro : UserMacro
{
// ...
}Better example - descriptive and unique:
public class SendEmailOnAlarmMacro : UserMacro
{
// ...
}Always keep in mind that your macro executes on the Security Center server. File paths refer to the server's file system, not the client's. Network resources must be accessible from the server.
Incorrect approach - assumes client file system:
public override void Execute()
{
string data = File.ReadAllText(@"C:\temp\config.txt");
}Correct approaches:
public override void Execute()
{
// Use UNC paths if accessing network resources
string data = File.ReadAllText(@"\\fileserver\share\config.txt");
// Or use server-local paths that exist on the server
string serverPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"Genetec", "MacroData", "config.txt"
);
}Warning
Common pitfalls:
- File paths refer to the server's file system, not the client's
- Network resources must be accessible from the server (check server account permissions)
- Environment variables are from the server context
- Time zones, regional settings, and installed applications are the server's
protected override void CleanUp()
{
// Unsubscribe from ALL events
Sdk.AlarmTriggered -= OnAlarmTriggered;
Sdk.EntityAdded -= OnEntityAdded;
// Dispose resources
someDisposableResource?.Dispose();
MacroLogger.TraceInformation("Cleanup completed");
}public Guid CameraGuid { get; set; }
public int RetryCount { get; set; }
public override void Execute()
{
if (CameraGuid == Guid.Empty)
{
MacroLogger.TraceWarning("CameraGuid parameter not set");
return;
}
if (RetryCount <= 0)
{
MacroLogger.TraceWarning("RetryCount must be positive");
return;
}
// Use parameters...
}public override void Execute()
{
try
{
// Your logic
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Macro execution failed");
throw; // Re-throw to mark macro as failed
}
}Remember:
-
CleanUp()is always called, even ifExecute()throws an exception - Re-throwing the exception marks the macro as failed
- Active transactions are automatically rolled back if the macro fails
For advanced scenarios requiring custom application domain configuration, inherit from UserMacroWithSetup instead of UserMacro.
Purpose: Control which application domain your macro runs in.
using Genetec.Sdk.Scripting;
using Genetec.Sdk.Scripting.Interfaces.Attributes;
[MacroParameters(SingleInstance = true)]
public class MyAdvancedMacro : UserMacroWithSetup
{
// ApplicationDomain is configured in Config Tool under "Default execution context"
// All macros with same ApplicationDomain share one app domain and SDK Engine
public override void Execute()
{
// Your macro logic
// Access the configured domain via MacroGroup or ApplicationDomain (both return the same value)
MacroLogger.TraceInformation(string.Format("Running in domain: {0}", MacroGroup));
}
protected override void CleanUp()
{
}
}When to use UserMacroWithSetup:
- You need to isolate macros in separate application domains
- One macro triggers events that another macro handles (avoid cross-domain issues)
- Performance optimization by grouping related macros (see Performance Optimization section)
Configuration:
- Create your macro inheriting from
UserMacroWithSetup - In Config Tool, open the macro's Default execution context tab
- Set the ApplicationDomain field (e.g., "MyMacroGroup")
- All macros with the same ApplicationDomain value share one app domain and one SDK Engine instance
Note
The ApplicationDomain property in UserMacroWithSetup is read-only and returns the same value as MacroGroup. The actual configuration is done in Config Tool, not by setting this property in code. The setter exists for backwards compatibility but does nothing.
By default, macros have access to a limited set of assemblies (see Available Assemblies section). To use additional .NET assemblies or third-party libraries, you must configure them using the MacroAssembly command in Server Admin.
Important
This procedure is manual and must be performed by a Security Center administrator with access to the Directory server. It cannot be automated from macro code.
To reference additional .NET Framework assemblies (e.g., System.Drawing.dll):
- On the Directory server, open Server Admin in a browser:
http://localhost/genetec/console - Navigate to Commands
- Select All commands (or uncheck User commands only)
- Find and select the MacroAssembly command
- When prompted, enter the full assembly name:
System.Drawing.dll - Restart the Macro Agent:
- Option A: Restart the Directory service
-
Option B: Kill
GenetecMacroAgent32.exein Task Manager (it will restart automatically)
- Your macro can now use the assembly
using System.Drawing;
using Genetec.Sdk.Scripting;
public class ImageProcessingMacro : UserMacro
{
public override void Execute()
{
// Now you can use System.Drawing
using (var bitmap = new Bitmap(640, 480))
{
// Process image
}
}
protected override void CleanUp()
{
}
}To use external DLLs (e.g., custom libraries, NuGet packages):
-
Copy the DLL to the Directory server:
- Recommended location:
C:\Program Files (x86)\Genetec Security Center\[YourDLL].dll - Or any accessible folder on the server
- Recommended location:
- If you have a failover Directory, copy the DLL there too (same path)
- Open Server Admin:
http://localhost/genetec/console - Go to Commands → MacroAssembly
- Enter the DLL path:
-
Relative path (from SC installation folder):
.\SharpSnmpLib.dll -
Absolute path:
C:\Program Files (x86)\Genetec Security Center\SharpSnmpLib.dll
-
Relative path (from SC installation folder):
- Restart the Macro Agent:
- Option A: Restart the Directory service
-
Option B: Kill
GenetecMacroAgent32.exein Task Manager
After this, you can reference the library in your macro code normally.
Important
Deployment considerations:
- The DLL must be copied to all Directory servers (primary + failover)
- Re-run the
MacroAssemblycommand after Security Center upgrades - If a new Directory server is added, copy the DLL and re-run the command
To remove an assembly reference:
- In Server Admin, run the MacroAssembly command
- Prefix the assembly name with a minus sign:
-System.Drawing.dll - Restart the Macro Agent
Here's a complete example showing how to add and use System.Drawing:
Step 1: Add the assembly via Server Admin
MacroAssembly command: System.Drawing.dll
Step 2: Restart Macro Agent and Config Tool
Step 3: Use in your macro
using System.Drawing;
using System.Drawing.Imaging;
using Genetec.Sdk.Scripting;
public class ImageProcessingMacro : UserMacro
{
public string OutputPath { get; set; }
public override void Execute()
{
// Create a simple image
using (var bitmap = new Bitmap(800, 600))
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.DrawString("Generated by Macro",
new Font("Arial", 24),
Brushes.Black,
new PointF(50, 50));
bitmap.Save(OutputPath, ImageFormat.Png);
MacroLogger.TraceInformation(string.Format("Image saved to {0}", OutputPath));
}
}
protected override void CleanUp()
{
}
}Note
The OutputPath would need to be a path accessible on the server (e.g., C:\Temp\output.png or a UNC path).
When a macro runs for the first time, the runtime compiles the C# source code into an assembly. This compiled assembly is cached and reused for subsequent executions.
Important
Recompilation adds significant startup delay. It occurs when:
- The macro source code is modified
- The referenced assemblies change
- The Genetec Server service restarts
The application domain also requires initialization on first use. The runtime creates the domain, initializes a shared SDK Engine, and authenticates with the Directory server. Once initialized, all macros in the same domain reuse this Engine.
| Scenario | Expected Startup Time |
|---|---|
| First execution after code change | Slowest (compilation + domain initialization) |
| First execution after server restart | Slow (domain initialization only) |
| Subsequent executions | Fast (everything cached) |
Tip
For time-critical macros, use the StayAlive pattern described below to keep the application domain initialized.
You can improve macro startup performance by grouping macros in the same ApplicationDomain and keeping the domain initialized with a persistent macro.
Strategy: Keep one macro running continuously to prevent the application domain from unloading, which keeps compiled binaries cached in memory.
using Genetec.Sdk.Scripting;
using Genetec.Sdk.Scripting.Interfaces.Attributes;
[MacroParameters(KeepRunningAfterExecute = true, SingleInstance = true)]
public class StayAliveMacro : UserMacroWithSetup
{
public override void Execute()
{
// Execute returns immediately but macro stays running
// This keeps the application domain alive
MacroLogger.TraceInformation("StayAlive macro started - keeping domain warm");
}
protected override void CleanUp()
{
MacroLogger.TraceInformation("StayAlive macro terminated");
}
}- In Config Tool, open the StayAlive macro
- Go to Default execution context tab
- Set ApplicationDomain:
MyMacroGroup(choose any name) - Save the macro
For all macros that should benefit from the performance boost:
- Inherit from
UserMacroWithSetup - Set the same ApplicationDomain value:
MyMacroGroup - All these macros will share the same app domain and SDK Engine instance
Create a Scheduled Task to start the StayAlive macro automatically:
- In Config Tool, go to System task → Scheduled tasks
- Create new scheduled task
- Set Recurrence: On startup
- Set Action: Run a macro
- Select Macro: Your StayAlive macro
- Save the scheduled task
Result: When the Directory starts, the StayAlive macro launches and keeps the application domain alive. All macros in MyMacroGroup will start faster because the domain is already loaded and warmed up.
Important
The StayAlive pattern is an advanced optimization technique. Only use it when you have a clear performance need and understand how to monitor and stop the macro if necessary. Ensure your StayAlive macro has no resource leaks.
Benefits:
- Reduced cold-start time for macros in the group
- Compiled macro binaries remain cached in memory
- Shared SDK Engine instance reduces memory overhead
- Ideal for frequently-executed macros
When debugging macros in production environments without attaching a debugger, use Server Admin to view macro logs in real-time.
- On the Directory server, open Server Admin
- In the Console window, look for log entries from your macro
- Macro logs appear with the macro class name as the logger name
If you don't see your macro's logs:
- In Server Admin, click the Add logger button
- Look for your macro by its class name (e.g.,
myMacro) - Select the logger and add it
- Choose the log level (Info, Debug, Warning, Error)
If your macro doesn't appear in the logger list:
- Add a
MacroLogger.TraceInformation()call in your macro'sExecute()method - Run the macro at least once
- Reload or restart Server Admin
- The logger should now appear in the list
using Genetec.Sdk.Scripting;
public class ProductionMacro : UserMacro
{
public Guid TargetEntity { get; set; }
public override void Execute()
{
MacroLogger.TraceInformation("Macro started");
MacroLogger.TraceDebug(string.Format("Processing entity: {0}", TargetEntity));
try
{
// Your logic
MacroLogger.TraceInformation("Operation completed successfully");
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Operation failed");
throw;
}
}
protected override void CleanUp()
{
MacroLogger.TraceInformation("Cleanup completed");
}
}Log Levels:
| Method | Level | Use For |
|---|---|---|
TraceInformation() |
Info | General operational messages (start, complete, key milestones) |
TraceDebug() |
Debug | Detailed diagnostic information (loop iterations, variable values) |
TraceWarning() |
Warning | Recoverable issues or unexpected conditions |
TraceError() |
Error | Errors and exceptions that prevent normal operation |
Tips:
- Use meaningful log messages that help diagnose issues
- Include relevant context (entity GUIDs, parameter values, etc.)
- Log at appropriate levels (avoid excessive Debug logging in production)
- Server Admin logs persist and can be reviewed after macro execution
Debugging macros is more challenging than debugging regular applications because they run inside the Security Center server environment. Use these strategies to diagnose and troubleshoot macro issues.
Use extensive logging in your macro code to follow execution flow and diagnose issues.
public override void Execute()
{
MacroLogger.TraceInformation("Execute started");
MacroLogger.TraceDebug($"Parameter value: {MyParameter}");
try
{
// Your logic
MacroLogger.TraceDebug("Reached checkpoint A");
var entity = Sdk.GetEntity(EntityGuid);
if (entity == null)
{
MacroLogger.TraceWarning($"Entity not found: {EntityGuid}");
return;
}
MacroLogger.TraceDebug($"Processing entity: {entity.Name}");
// More logic
MacroLogger.TraceInformation("Operation completed successfully");
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Execute failed");
throw; // Re-throw to trigger macro aborted event
}
}Best practices:
- Log at the start of
Execute()to confirm the macro was triggered - Log major decision points and branches in your logic
- Log entity GUIDs, parameter values, and other relevant context
- Log exceptions with full details before re-throwing
- Remove or reduce verbose logging once the macro is stable
Use Console.WriteLine() for quick diagnostic output during development:
public override void Execute()
{
Console.WriteLine("Macro started");
Console.WriteLine($"Parameter: {MyParameter}");
// Your logic
Console.WriteLine("Macro completed");
}Console output may appear in the server's console if running interactively, or can be captured in debug logs. This is useful for quick debugging but MacroLogger is preferred for production code.
Compile-time errors are caught when you save the macro in Config Tool:
- Click Check syntax to validate code before saving
- Syntax errors show in a dialog with line numbers and descriptions
- Fix all compilation errors before attempting to run the macro
Runtime errors occur during execution:
- Check macro events (started/completed/aborted) in Security Desk
- If a macro aborts, check the event details for exception information
- Review Directory logs for full stack traces and error messages
Enable the debug console to capture runtime messages and traces:
For Security Desk:
- Open Security Desk
- Go to About > Debug Console > Enable
- Restart Security Desk
- Navigate to
http://localhost:6020/console/in a web browser
For server-side macros:
- Use Genetec Server Admin > Logs to access Directory logs
- Enable trace levels for more detailed logging
- Look for macro-related entries around the time of execution
Always handle exceptions gracefully to prevent abrupt macro failures:
public override void Execute()
{
try
{
// Risky operation (network call, file access, etc.)
PerformExternalOperation();
}
catch (IOException ioEx)
{
MacroLogger.TraceError(ioEx, "File operation failed");
// Handle file-specific error
}
catch (Exception ex)
{
MacroLogger.TraceError(ex, "Unexpected error");
throw; // Re-throw if recovery isn't possible
}
}Error handling guidelines:
- Catch specific exceptions first, then general exceptions
- Log all exceptions with context before handling or re-throwing
- Consider whether to absorb the error (return) or propagate it (throw)
- For critical macros, implement retry logic or fallback behavior
- Validate inputs and check for null references before use
Test in isolation:
- If possible, test macro logic outside Security Center first
- Use unit tests for complex algorithms or business logic
- Validate parameter handling with edge cases (null, empty, invalid values)
Test in staging:
- Always run new macros in a test/staging environment first
- Test with realistic data and conditions
- Verify that the macro completes successfully and produces expected results
- Check for resource leaks (memory, file handles, connections)
Test automation triggers:
- If using event-to-action, test both manual execution and automatic triggers
- Verify that context parameters are passed correctly from events
- Test edge cases (what if the triggering entity doesn't exist?)
Load testing:
- For macros that run frequently, test under load
- Verify performance with multiple concurrent instances
- Monitor server resource usage (CPU, memory) during execution
If your macro makes changes to the system (creates entities, changes door states, triggers alarms), those actions are recorded in Security Center Audit Trails. Run an audit report to confirm the macro's effects and troubleshoot unexpected behavior.
Macro doesn't start:
- Check if macro is in Draft mode (toggle off in Config Tool)
- Verify user has "Execute macros" privilege
- Check if macro entity is in an accessible partition
- Review event logs for "Macro aborted" events with error details
Macro hangs or runs too long:
- Check for infinite loops without delays
- Verify that blocking operations (network calls, file I/O) complete
- Use System Status > Macros to stop the macro manually
- Add timeouts to long-running operations
SDK operations fail:
- Verify entities exist before accessing them
- Check that the macro has appropriate permissions (limited access rights may restrict certain operations)
- Ensure entity types match expected types (cast safely)
Parameters are null or wrong:
- Verify default execution context is configured in Config Tool
- Check if event-to-action or scheduled task overrides context correctly
- Initialize properties with default values in code as a fallback
Macros run server-side under the Macro Agent process. Starting in Security Center 5.8, macros can run with limited access rights to prevent security risks. On new installations, this is enabled by default. If you upgraded from a pre-5.8 system, ensure this setting is enabled in Genetec Server Admin under Directory settings ("Run macros with limited access rights").
With limited access rights enabled:
- Macros run in a restricted context
- Cannot create Admin user accounts
- Cannot perform certain high-risk configuration changes
- Some SDK operations may be denied or require special permissions
When developing macros, be aware that certain operations may not be available if limited access rights are enabled. Test your macro in an environment that matches your production security settings.
Warning
For security, macros must not:
- Open inbound network listeners (web servers, TCP sockets, etc.)
- Access Security Center databases directly (use SDK only)
- Execute arbitrary shell commands from untrusted input
- Store or transmit sensitive credentials
Always interact with Security Center through the SDK APIs provided.
Macros are compiled and executed by the Directory using a limited set of preconfigured assemblies (a subset of the .NET Framework plus key Genetec SDK assemblies such as Genetec.Sdk.dll and Genetec.Sdk.Scripting.Interfaces.dll).
The exact list of loaded assemblies depends on the Security Center version and on any assemblies added by an administrator using the MacroAssembly command. If your macro fails to compile due to a missing assembly reference, you must ask an administrator to add that assembly via MacroAssembly in Server Admin.
To use macros, the Security Center system requires the Macro SDK license feature. Macros do not require SDK development certificates.
What you need:
- Security Center system with the "Macro SDK" license feature enabled
- No SDK development certificate required
- Platform SDK overview - Working with the Platform SDK
- SDK Transactions - Transaction management
-
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.