Dependencies & isolation

Building & deploying

Dependencies & isolation

Which assemblies the platform provides, when a third-party library belongs next to your plugin, and how each plugin's load context resolves its references.

What the platform provides and what you ship

The SabrTrader.Sdk meta-package brings in the contract assemblies you compile against. The platform ships those assemblies itself, so you reference them at build time and leave them out of the plugin folder:

Assembly Provided by the platform? Deploy with your plugin?
SabrTrader.Pipeline.Contracts Yes No
SabrTrader.Pipeline.Venues.Contracts Yes No
SabrTrader.Pipeline.Strategies.Contracts Yes No
SabrTrader.Pipeline.AddOns.Contracts Yes No
The .NET runtime / framework assemblies Yes No
A library the platform does not ship (a CSV parser, an exchange SDK) No Yes
A library the platform also ships Yes No. Your plugin gets the platform's copy (see Versions).
Your own plugin DLL Not applicable Yes
Rule of thumb. Assemblies named SabrTrader.* and .NET framework assemblies come from the platform. Third-party libraries that only your plugin uses go next to your plugin DLL.

Third-party dependencies

If your plugin references a library the platform does not ship, copy that library's DLL into the plugin folder next to your plugin DLL. Your plugin's load context resolves it from the plugin folder: through your plugin's .deps.json when one is present, otherwise by file name (<assembly name>.dll). A NuGet package can bring more than one DLL; copy each one your plugin uses.

The auto-deploy target copies your primary output only. The SDK's DeploySabrTraderPlugin target copies $(TargetPath) (your DLL) and its PDB, not your dependencies. Copy a third-party DLL into the plugin folder yourself, or add your own copy step to the project.

The plugin folder is flat and shared by every plugin, and every DLL in it is also inspected as a candidate plugin. A library DLL registers nothing, so this costs only load time.

The isolation model

Each plugin DLL is loaded into its own collectible AssemblyLoadContext, named Plugin:<file name>. A library your plugin loads from the plugin folder lives in that context, so its statics are private to your plugin, and one plugin's dependencies stay out of another's. When your plugin references an assembly, its load context resolves the reference in this order:

  1. Assemblies the platform ships resolve to the platform's copy. This covers the SDK contract assemblies, the .NET framework, and every other library in the platform's installation folder.
  2. Anything else is loaded from the plugin folder into your plugin's own context, through your plugin's .deps.json when present, otherwise by file name.

At startup the platform loads every DLL in the folder this way, catalogs its types, and writes a summary line plus any load or registration errors to the Control Center Log tab. A malformed DLL, a missing dependency or a type that fails to register is logged, and the rest of the platform continues. Reloads of a changed DLL follow the same path in a fresh load context.

Why contracts come from the platform

The platform and your plugin have to agree on the contract types: IIndicator, Strategy, IVenuePlugin and the rest. In .NET a type's identity is its name plus the assembly instance it was loaded from. If a contract assembly were loaded a second time inside your plugin's context, the runtime would hold two IIndicator types that look identical but are not interchangeable, and the platform would not recognise your indicator.

The first rule in the resolution order prevents this: every contract reference resolves to the platform's own assembly, so typeof(IIndicator) is the same type object on both sides. Contract copies in the plugin folder are never used for this, which is why there is no reason to ship them. Your private third-party libraries have no shared-identity requirement, so they load inside your plugin's context from the plugin folder.

Plugins do not share types with each other. If plugin A references plugin B's DLL, A's load context loads its own copy of B, with its own type identities and statics. Put code that two plugins share into one assembly, or have them communicate through SDK types.

Versions & targeting

  • Target framework. The SDK assemblies target net10.0 and the platform runs on .NET 10, so your plugin targets net10.0.
  • Libraries the platform ships win. When the platform ships a library your plugin also uses, your plugin runs against the platform's version whenever that version is at least the one you compiled against. Compile against a version at or below the platform's, and test against the platform release you target.
  • One file name per library. The plugin folder is shared by all plugins, so it can hold only one Library.dll. Two plugins that need different versions of the same third-party library cannot both ship it; agree on one version.
  • SDK version. A plugin compiled against an SDK version runs on a platform that ships that contract version or a compatible later one. Rebuild against the SDK version that matches the platform release you target.