Discovery & loading
How a folder on disk becomes a running plugin — and the one detail that explains most loading problems.
At startup
- The host resolves
plugins/next to the executable. - For each subfolder, it reads
plugin.json. No manifest, no plugin. - It checks the
typediscriminator and whetherhostApiVersionfalls inside the range this host supports. Out of range, the plugin is skipped rather than half-loaded. - It loads the
entryAssemblyinto a fresh, isolated load context, resolved against that plugin's own.deps.json— which is why every plugin can carry its own driver version without colliding with any other. - It reflects for the type the plugin type expects (
IDbProvider,IToolPlugin, and so on) and activates it. A tool assembly may ship several tools; all are instantiated. - It scans the loaded plugin for the optional capabilities — settings panes and keyboard shortcuts register themselves at this point.
Loading never throws back at the host: a failure is captured per plugin and logged, so one broken plugin can't take the app down with it.
Isolation, and the one exception
Each plugin gets its own AssemblyLoadContext. Two plugins can therefore depend on different,
incompatible versions of the same driver and neither will notice the other.
SqlExplorer.Sdk itself, falling back to the host's copy — so IDbProvider keeps
a single type identity across the boundary. That is precisely why every plugin project sets
Private="false" on the SDK reference: SqlExplorer.Sdk.dll must not be copied
into the plugin's own folder.If a plugin loads but the host says it doesn't implement the interface it obviously implements, this is almost always the cause: two copies of the SDK, two distinct types with the same name.
What ships in the folder
Set CopyLocalLockFileAssemblies so the full private dependency closure lands in the folder, and
keep the .deps.json — without it the load context has nothing to resolve your driver
against.
SQL Explorer