Building a tool
A tool contributes an action rather than an engine: a menu item on the schema tree that collects some input and runs against the selected connection or node. Schema Diff is a tool plugin; so is Universal Backup.
Tools reference the same SqlExplorer.Sdk assembly as providers, and get handed the live
IDbProvider for the connection they run on — so a tool can read schema and run queries on
any engine without a driver dependency of its own.
The contract: IToolPlugin
| Member | Purpose |
|---|---|
Id | Stable id. One assembly may contain several IToolPlugin classes — all are loaded — so this need not match the manifest id. |
Target | Which tree nodes offer the tool. |
Fields | Route A input declarations; the host renders a generic dialog. Empty when the tool brings its own view. |
IsDestructive | Show a destructive-action confirmation before running. |
ExecuteAsync | Runs the tool. inputs holds the collected values keyed by ToolField.Key; report progress through progress. |
Where the tool appears: ToolTarget
The tool shows on a node when the node's provider is in ProviderIds and its kind is in
NodeKinds. The connection root has no node kind, so a whole-connection tool sets
IncludeConnectionRoot rather than trying to express the root through NodeKinds.
What a run receives
IToolHost
| Member | Purpose |
|---|---|
GetPluginSetting(key) | Read the plugin's own persisted settings, as configured in Settings › Plugins. |
ListConnections() / ListDatabasesAsync(id, ct) | The user's other connections, and the databases on one of them. This is how a tool offers a destination. |
OpenConnection(id, database) | A live provider + profile for another connection, so a tool can run against a second database. |
OpenQueryEditor(sql) | Hand generated SQL to a query tab instead of running DDL yourself. Schema Diff ends this way: the user reviews the migration before anything runs. |
Route A: declared fields
ToolFieldType is Text | Password | Choice | File | Bool | ConnectionPicker |
DatabasePicker. A Password field is routed to the OS keychain and never written to disk; a
File field gets a Browse button wired to the host's picker. ConnectionPicker and
DatabasePicker are a dependent pair: pick a connection and the database dropdown fills itself
from it.
Route B: your own view
When the inputs are interdependent, or the flow deserves a designed layout, supply an Avalonia view instead of the generated form:
Values still flow through IToolUiContext.GetValue/SetValue, so ExecuteAsync is
unchanged — the host still renders the dialog's chrome (checklist, log, progress bar, action bar) around
your view.
Because the returned Control is an Avalonia type shared across the ALC boundary, reference
Avalonia with ExcludeAssets="runtime" — see
Plugin capabilities.
Tool manifest
Identical to a provider's, but type is "tool" and hostApiVersion
tracks the tool contract (ToolHostApi.Version), which versions separately from the
provider contract.
Declare the newest version whose members you actually use — not simply the newest that exists. A tool that declares an older version keeps loading in hosts that predate the newest one.
SQL Explorer