What an Event Server plugin actually is

The XProtect Event Server is the headless Windows service that owns the Rules and Events engine — it ingests events from every source in the system (device events, generic events, other MIP plugins, third-party feeds) and evaluates them against configured rules to drive actions: alarms, notifications, output activation, recording triggers. An Event Server plugin is a MIP SDK plugin that runs inside this process rather than inside Smart Client. It never renders UI of its own — it's server-side, headless, and running whenever the Event Server service is running, independent of whether any operator is logged in anywhere.

This makes it the natural home for translating a third-party system's state into XProtect's event model: a fence controller alarm, a building-management-system fault, a custom business rule, or a scheduled integrity check — anything that should be able to trigger a rule but doesn't originate from a device XProtect already understands. Where our Smart Client plugin guide covers the operator-facing side of the MIP SDK, this one covers the always-on, server-side side of the same SDK.

What the MIP SDK provides for Event Server plugins

The pieces of the SDK relevant here are a different corner of the same assembly set covered in the Smart Client guide:

  • VideoOS.Platform.Background — the Background base class Event Server plugins inherit from, alongside the shared PluginDefinition entry point every MIP plugin type uses.
  • VideoOS.PlatformEnvironmentManager for registering custom event/alarm Kinds and firing them, the item hierarchy for referencing cameras and servers, and Configuration.Instance for reading and persisting plugin configuration.
  • VideoOS.Platform.Messaging — the same publish/subscribe bus Smart Client plugins use, useful when a Background plugin needs to react to system state changes rather than only originate events.

A single plugin assembly can register both a Background plugin and Smart Client plugin types from the same PluginDefinition, sharing a plugin GUID — but the two run in entirely separate processes on potentially separate machines, so treat them as independently deployable components that happen to ship together.

The plugin entry point: PluginDefinition and Background

Event Server plugins share the same PluginDefinition entry point pattern as every other MIP plugin type — Event Server discovers the subclass via reflection when it scans the plugin's assembly, then reads whichever plugin-type lists are populated.

C# — plugin entry point
using System;
using System.Collections.Generic;
using VideoOS.Platform;
using VideoOS.Platform.Background;

namespace Xplug.EventServer.Sample
{
    public class SamplePluginDefinition : PluginDefinition
    {
        private static readonly Guid PluginIdValue =
            new Guid("4A1E7C2B-9D3F-4E6A-8C1B-2F5A9D0E3B44");

        public override Guid Id => PluginIdValue;
        public override string Name => "Xplug Event Server Plugin";
        public override string VersionString => "1.0.0";
        public override string Manufacturer => "Xplug.in";

        public override List<Background> BackgroundPlugins =>
            new List<Background> { new SampleBackgroundPlugin() };
    }
}
C# — Background plugin
using System;
using VideoOS.Platform;
using VideoOS.Platform.Background;

namespace Xplug.EventServer.Sample
{
    public class SampleBackgroundPlugin : Background
    {
        public override Guid Id =>
            new Guid("1B2C3D4E-5F60-4718-9A2B-3C4D5E6F7081");
        public override string Name => "Xplug Field System Bridge";

        public override void Init()
        {
            // Keep this fast: Event Server waits on every plugin's Init()
            // before it finishes starting up. Do polling or slow I/O on
            // a thread you own, started here but not awaited here.
            EnvironmentManager.Instance.RegisterKind(SampleAlarmKind.Definition);
            SampleFieldSystemWorker.Start();
        }

        public override void Close()
        {
            SampleFieldSystemWorker.Stop();
        }
    }
}

As with the Smart Client plugin types, exact base-class members shift slightly between MIP SDK releases — treat the shape above as illustrative of the pattern rather than a drop-in reference, and check the SDK version's own sample projects before committing to a signature.

Firing custom events and driving the Rules engine

A Background plugin earns its place by turning something XProtect doesn't natively understand into something the Rules and Events engine does. That means two things: registering a custom event or alarm Kind so it becomes a selectable trigger in Management Client's Rules and Events configuration, and then firing instances of it when the underlying condition occurs.

C# — registering and firing a custom event kind
using System;
using VideoOS.Platform;

namespace Xplug.EventServer.Sample
{
    public static class SampleAlarmKind
    {
        public static readonly Guid Definition =
            new Guid("6E2A9C10-4B3D-4F7E-8A1C-9D2E3F4A5B60");

        public static void FireFieldSystemAlarm(string deviceId, string description)
        {
            var header = new EventHeader
            {
                EventHeaderGuid = Definition,
                Message = description,
                Sender = new Item(Guid.Empty, Kind.Server)
            };
            EnvironmentManager.Instance.FireEvent(header);
        }
    }
}

Once registered, the custom Kind shows up in Management Client under Rules and Events alongside XProtect's built-in event types, and an administrator can build ordinary rules against it — "when Field System Alarm occurs on Device X, activate output Y and notify group Z" — without knowing or caring that the trigger originated from a plugin rather than a supported device. This is the payoff of building on the Event Server rather than bolting alerting logic directly onto a third-party integration: every downstream capability XProtect already has for its own events (schedules, time constraints, multi-condition rules, alarm escalation) becomes available to your custom one for free.

Threading and reliability inside a shared process

A Background plugin doesn't get its own process or its own fault boundary — it runs inside the same Event Server service instance as every other Background plugin on that server, and as the rule engine evaluating alarms for the entire site. That changes the risk calculus compared to a Smart Client plugin, where a crash affects one operator's session. An unhandled exception on a plugin's own thread, a blocking synchronous call inside an event handler, or a slow Init() that delays service startup all have site-wide blast radius: rules stop evaluating, alarms stop firing, for every camera and every operator, not just the ones related to your integration.

In practice this means: never block inside Init() or inside a message-bus callback — hand off to your own thread or timer immediately; wrap your polling loop's body in a try/catch that logs and continues rather than lets an exception propagate; and treat any third-party call (HTTP, Modbus, a vendor SDK) as something that can hang, with its own timeout, so a single unresponsive field device can't stall the whole plugin.

Deployment: getting a plugin from build to a running Event Server

  1. Build in Release configuration, matching the target Event Server's .NET Framework version and bitness.
  2. Copy the output to a subfolder under %ProgramFiles%\Milestone\XProtect Event Server\MIPPlugins\<YourPluginName>\, including any third-party dependencies.
  3. Restart the Event Server service. On startup it scans MIPPlugins the same way Smart Client does, loads each assembly, and instantiates any PluginDefinition subclass it finds.
  4. Verify the load from Management Client's MIP Plugins node, and confirm the custom event/alarm Kind appears as a selectable trigger under Rules and Events.
  5. Watch the Event Server log during first startup after deployment — a missing dependency or a version mismatch against the installed XProtect release surfaces here, not as a UI error, since there's no UI to show one in.

As with Smart Client plugins, certification through Milestone's MIP Verified programme is worth planning for early rather than retrofitting — it validates the plugin against Milestone's compatibility and stability expectations before it runs inside a customer's production Event Server, where the cost of an unstable plugin is the whole rule engine, not one workstation.

Where this gets hard in practice

The mechanics above are genuinely enough for a working prototype. What's hard in a production Event Server plugin is everything that only shows up under real load: keeping a polling worker alive across the field system's own outages without leaking threads, designing the custom Kind's payload so it carries enough context for a useful rule without becoming a dumping ground, and handling an Event Server failover cleanly if the deployment runs Event Server in a redundant configuration. This is the part of custom Milestone XProtect plugin development we specialise in at Xplug.in — architecture, MIP Verified certification, and keeping a Background plugin stable across years of XProtect upgrades, not just the first working build.

Need a Milestone XProtect Event Server plugin built and certified? Xplug.in is a Milestone MIP Verified partner with 140+ plugins shipped since 2014.

Schedule a technical demo