Skip to content

Profiling a Plugin Run

Peter McDonald edited this page Aug 12, 2026 · 5 revisions

Profiling a Plug-in Run

Capture a real execution of your plug-in from Dataverse, download it, and replay it locally against the exact context the platform passed in — no live org needed to re-run it, and no Trace() archaeology.

Every screenshot on this page is taken from the automated end-to-end suite while it drives the real UI, so what you see is what the extension actually does. The control being used in each step is outlined in orange. (The environment name and URL are blanked out; you will see your own there.)

Preview feature. Plug-in debugging ships behind dataverse-powertools.previewFeatures, off by default. Tick Preview features in the panel footer before the Debugging block appears. Sign-off checklist: #224.

Before you start

You need Why
A connected environment The profiler runs in the org, not on your machine
A deployed plug-in with a registered step You can only profile a step that exists and is enabled
Windows, for Profile next run The capture tool is .NET Framework. On macOS/Linux, capture in the Plugin Registration Tool and use Download a run instead
The Plugin Profiler solution The extension offers to install it for you the first time

Where these actions live

Everything is in the Debugging block of the plug-in card. Active profiles underneath shows anything currently being profiled — worth knowing about, because a step stays disabled while it is profiled.

The Debugging block on the plug-in card: Profile next run, Download a run, Replay & debug, and the Active profiles list

Two ways to choose which step to profile

An assembly can register many steps, so the first decision is always which step. Two routes, differing only in how you pick.

Route A — the panel button

Profile next run starts a capture for this component. If more than one step is profilable it first asks "Profile which plugin step?"; with exactly one it goes straight on.

The Profile next run button in the Debugging block, outlined in orange

Route B — the per-step CodeLens

Above every [CrmPluginRegistration(...)] attribute sits a Profile: Off / Profile: On CodeLens. Clicking it profiles that step — the registration you are looking at — so there is no picker to answer. This is the quickest route when you are already in the code, and the label doubles as an at-a-glance indicator of which steps are armed.

The Profile: Off CodeLens above a CrmPluginRegistration attribute, outlined in orange

Once profiling starts, the label flips to Profile: On:

The same CodeLens now reading Profile: On

Stop profiling from the Active profiles list, not the lens. Clicking Profile: On to stop does not currently work — it reports "No deployed step matches …" and profiling stays on, leaving your step disabled (#251). Use the stop button in the card's Active profiles block instead.

Step by step

1. Arm the capture

Use either route above. The extension enables profiling on the step and, for package-deployed plug-ins, first populates the assembly content the profiler needs — Dataverse leaves that empty for pac/NuGet packages, which is why profiling a package plug-in used to be impossible. The output shows [Profiler] Started profiling … (panel button) or [Profiler] Profiling ON for … (CodeLens).

2. Trigger your plug-in, then press Continue

The extension waits while you make the thing happen that fires your step — create the record, run the flow, press the button in the app. Then press Continue.

The dialog asking you to trigger the plug-in, with Continue outlined in orange

An asynchronous step runs in a background job, so give it a few seconds after the trigger.

3. Pick the captured run

Continue lists the captured executions. Tick the one you want — it is a multi-select, so you can take several at once.

The captured-run picker with a profile selected

The chosen profile is saved to profiles/ in your component folder.

4. Turn the capture into a replay test

Replay & debug generates a unit test that replays the captured context through your plug-in, plus a small shared harness (DvptProfileReplay.cs) in your test project.

The Replay & debug button, outlined in orange

With more than one profile in profiles/, it asks "Replay which profile?" first.

5. The generated test

The generated Replay_<Type>_<timestamp>.cs open in the editor

It decodes the .profile, rebuilds the IPluginExecutionContext the platform passed in, and calls your plug-in's Execute in-process — no child AppDomain and no live org — so it runs anywhere dotnet test runs, including CI.

6. Run it

Run it like any other test: the Testing side bar, Run Tests on the plug-in card, or dotnet test. Green means the captured production context replayed through your code without throwing.

Debugging it (breakpoints) needs the C# extension — the Testing view's Debug action launches a coreclr session, which ms-dotnettools.csharp provides. Note that Run/Debug Test at Cursor and the gutter icons do not currently work for plug-in tests (#252); use the Testing view's buttons.

What happens under the hood

  1. Enable profiling — the Plugin Profiler clones your step and disables the original, so executions route through the profiler.
  2. Capture — your trigger fires the profiled step; the profiler persists the execution context.
  3. Download — the extension fetches the persisted profile into profiles/.
  4. Generate — it writes a test that decodes the profile (base64 → deflate → report XML → PluginExecutionContext) and invokes your plug-in against it.
  5. Stop profiling — the clone is removed and your original step is re-enabled.

Step 5 is the one to remember: a step left profiled stays disabled, so it will not fire at all until profiling is stopped.

Troubleshooting

"N step(s) are registered for … but all are DISABLED" — profiling was left on. Stop it from the Active profiles list and the step comes back. (Before 1.0.2 this said "No registered plugin steps to profile — deploy your plugin and register a step first", which was impossible advice for a step you already had.)

"No steps registered for assembly …" — the deployed assembly name does not match this project, or the step never registered. Check the [CrmPluginRegistration] attribute and redeploy with Build & deploy package.

Nothing captured — an asynchronous step may not have finished, or the trigger did not match the step's message/table filter. The profiler only captures what actually fires.

See also

Clone this wiki locally