Skip to content

howto debug plugin

PhuocLe edited this page Jun 20, 2026 · 1 revision

Debugging a Dataverse plugin is hard when the failure only happens inside the sandbox. DynamicsCrm.DevKit helps by writing the real RemoteExecutionContext to Plugin Trace Log as a copy-pasteable JSON snippet, then replaying that context locally from a Console project.

What DevKit Gives You

Part Why it matters
Shared Project Template Contains DevKitJson, compression helpers, and ITracingService.DebugContext(context).
Server Project Template Hosts the plugin assembly and deployment scripts.
C# Plugin Item Template Creates the plugin class that receives IPluginExecutionContext and ITracingService.
Console Project Template Contains Helper.DebugPluginWith<T>(json, App.Service) for local replay against Dataverse.
Test Project Template and Shared Test Project Template Useful when the trace scenario should become a repeatable FakeXrmEasy unit test.

How It Works

DebugContext serializes the current plugin execution context using DevKitJson. The output is written to Plugin Trace Log as C# code:

var json = @"{...}".Replace("'", "\"");

If the context is larger than the Plugin Trace Log limit, DevKit writes a compressed form instead:

var json = "...".Decompress();

The generated Console Project Template already contains the replay hook:

private static void DebugPlugin()
{
    //var json = "";
    //Helper.DebugPluginWith<???>(json, App.Service);
}

Step 1: Enable Plugin Trace Log

In Dataverse, enable Plugin Trace Log from System Settings > Customization.

For debugging, use a setting that captures the traces you need. During active development, logging all plugin traces is usually easier. In shared environments, switch back to a safer setting after the issue is captured.

Step 2: Add DebugContext To The Plugin

In the plugin code created from C# Plugin Item Template, get the tracing service and execution context, then call DebugContext.

public void Execute(IServiceProvider serviceProvider)
{
    var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
    var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

    tracingService.DebugContext(context);

    // Your plugin logic.
}

DebugContext is compiled under #if DEBUG, so deploy a Debug build when you want trace replay data. Do not leave noisy debug tracing enabled in production longer than needed.

Step 3: Deploy The Debug Plugin

Use the server project deployment script or the CLI server command.

.\deploy.debug.bat

or:

devkit server --auth FromPac --pacprofile DEV --json DynamicsCrm.DevKit.Cli.json --profile DEBUG

See Server Project Template and CLI server command for the deployment profile.

Step 4: Reproduce The Dataverse Scenario

Run the user action that triggers the plugin:

  • create or update a row,
  • qualify a lead,
  • call a Custom API,
  • run the business process that fails.

Then open Plugin Trace Log and find the trace entry for the failing execution. Copy the generated var json = ...; snippet from the trace message.

Step 5: Use AI And MCP To Extract The Debug JSON

If you use an AI agent connected to the DevKit MCP server, you do not need to manually copy the full trace message.

Open the Plugin Trace Log row in Dataverse, copy the browser URL, and ask the AI:

Use DevKit MCP to parse this Plugin Trace Log URL, open the trace log detail, extract the DebugContext JSON snippet, and update my Console project DebugPlugin method.
<paste Plugin Trace Log URL>

The AI can use:

MCP tool Purpose
parse_record_url Extracts the Plugin Trace Log record ID from the Dataverse URL.
get_plugin_trace_logs Opens the trace log detail and reads the full messageblock and exception details.

For compressed traces, ask the AI to keep the generated .Decompress() call. For normal traces, ask it to preserve the generated Replace("'", "\"") form. The goal is to update the Console project with the exact trace payload, not a summarized version.

Useful prompt:

Here is the Plugin Trace Log URL. Extract the DevKit DebugContext snippet from messageblock and replace the json assignment inside Program.DebugPlugin().

Step 6: Paste The JSON Into A Console Project

Create a project from Console Project Template if you do not already have one. Configure its connection so App.Service points to the same Dataverse environment or to an environment with equivalent data.

In Program.cs, paste the trace snippet and call Helper.DebugPluginWith<T>.

private static void DebugPlugin()
{
    var json = @"{'__type':'RemoteExecutionContext'}".Replace("'", "\"");
    Helper.DebugPluginWith<PreUpdateAccount>(json, App.Service);
}

If the trace used compressed output, keep the generated Decompress() call:

private static void DebugPlugin()
{
    var json = "base64-compressed-context".Decompress();
    Helper.DebugPluginWith<PreUpdateAccount>(json, App.Service);
}

Then call DebugPlugin() from Main.

static void Main()
{
    DebugPlugin();
}

Now set breakpoints in the plugin class and run the Console project. DevKit rebuilds the service provider, plugin execution context, tracing service, and organization service factory from the trace data so the plugin can be replayed locally.

Step 7: Turn The Trace Into A Repeatable Test

After the bug is understood, move the scenario into a test project.

Use Test Project Template with Shared Test Project Template. The shared test helpers support:

var ctx = PluginContextBuilder.FromJson(_context, json).Build();
_context.ExecutePluginWith<PreUpdateAccount>(ctx);

or:

_context.ExecutePluginFromJson<PreUpdateAccount>(json);

This turns a production trace into a regression test.

Common Problems

Problem Fix
No JSON appears in Plugin Trace Log Confirm Plugin Trace Log is enabled and the plugin assembly was deployed from a Debug build.
Trace says the context exceeds 10 KB Reduce images/attributes for the plugin step, or reproduce with less data. DevKit already tries compact JSON and compression.
Console replay hits Dataverse data differences Point the Console project to the same environment or create the required data before replay.
Breakpoints do not hit Make sure the Console project references the current plugin project output and you are debugging the Console startup project.

Related

Clone this wiki locally