Building a Custom Plugin in Dataverse
and Calling It from Power Automate
A step-by-step guide for developers
March 2026 |
Power Platform Series
What Are We Building?
In this post, we will walk
through how to write a simple C# plugin, register it in Microsoft Dataverse,
expose it as a custom API action, and finally call it from Power Automate as an
unbound action.
To keep things simple, our
plugin will do one thing: add two numbers together. The formula is:
a = b + c
Simple math — but the plumbing
around it covers everything you need to know to build real-world business logic
in Dataverse.
What You Need Before Starting
|
Tool |
Why You Need It |
|
Visual
Studio |
Write
and build the C# plugin |
|
Power
Platform / Dataverse environment |
Deploy
and test the plugin |
|
Plugin
Registration Tool (PRT) |
Register
the DLL in Dataverse |
|
.NET
Framework 4.6.2 |
Required
target framework for Dataverse plugins |
|
Microsoft.CrmSdk.CoreAssemblies
(NuGet) |
Gives
you IPlugin and Dataverse base classes |
|
Important: Dataverse plugins
only support .NET Framework 4.6.2. Do NOT use .NET 5, 6, 7, or 8. This is the
most common mistake developers make. |
Step 1 — Create the Visual Studio Project
Open Visual Studio and create a
new project:
1.
File > New > Project
2.
Choose Class Library (.NET Framework)
3.
Set the target framework to .NET Framework 4.6.2
4.
Name the project — for example, MyCalcPlugin
Then install the Dataverse SDK
via NuGet Package Manager Console:
Install-Package Microsoft.CrmSdk.CoreAssemblies
|
After installing, confirm the
DLL reference path contains 'net462' — for example:
packages\Microsoft.CrmSdk.CoreAssemblies.9.x.x\lib\net462\Microsoft.Xrm.Sdk.dll |
Step 2 — Write the Plugin Code
Replace the default class with
this code. The plugin reads two input parameters (b and c), adds them together,
and writes the result to an output parameter (a).
using Microsoft.Xrm.Sdk;
using System;
namespace MyCalcPlugin
{
public class
AddNumbers : IPlugin
{
public void
Execute(IServiceProvider serviceProvider)
{
var context =
(IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
var tracer =
(ITracingService)
serviceProvider.GetService(typeof(ITracingService));
try
{
decimal b
= (decimal)context.InputParameters["b"];
decimal c
= (decimal)context.InputParameters["c"];
decimal a
= b + c;
context.OutputParameters["a"] = a;
tracer.Trace($"Result: {b} + {c} = {a}");
}
catch
(Exception ex)
{
throw new
InvalidPluginExecutionException($"Error: {ex.Message}");
}
}
}
}
Build the project in Release
mode. Your DLL will be in the bin\Release\ folder.
Step 3 — Sign the Assembly (Required)
Dataverse requires all plugin
DLLs to be strongly signed. Without signing, the Plugin Registration Tool will
reject the file.
5.
Right-click the project in Solution Explorer >
Properties
6.
Go to the Signing tab
7.
Check 'Sign the assembly'
8.
In the dropdown, choose New... and create a key file
(e.g. MyCalcPlugin.snk)
9.
Leave password protection unchecked for simplicity
10. Click
OK, then Clean Solution and Rebuild
To verify the signing worked,
run this in a Developer Command Prompt from the bin\Release\ folder:
sn.exe -v MyCalcPlugin.dll
|
You should see: Assembly
'MyCalcPlugin.dll' is valid. If you see 'Strong name validation failed',
delete bin\ and obj\ folders and do a full Rebuild. |
Step 4 — Create the Custom Action in Dataverse
The Custom Action is what
creates the message that your plugin listens to. Think of it as the API
contract — it defines the input and output parameters.
11. Go
to make.powerapps.com and open your solution
12. Click
New > Automation > Process
13. Set
Category to Action and Entity to None (global) — this makes it unbound
14. Give
it a name, for example AddNumbers
Then add parameters in the
Process Arguments section:
|
Name |
Direction / Type / Required |
|
b |
Input |
Decimal Number | Required |
|
c |
Input |
Decimal Number | Required |
|
a |
Output
| Decimal Number |
Save and Close, then click
Activate. The unique name of your action (visible in the Name field) will look
like new_AddNumbers — note this name, you will need it in the next steps.
|
Do not add any workflow steps
inside the action designer. The plugin handles the logic — the action just
defines the parameters. |
Step 5 — Register the Plugin in PRT
The Plugin Registration Tool
(PRT) connects your DLL to Dataverse. You can get it from NuGet or install via
the Power Platform Tools extension in Visual Studio.
Register the Assembly
15. Open
PRT and connect to your Dataverse environment
16. Click
Register > Register New Assembly
17. Browse
to your bin\Release\MyCalcPlugin.dll
18. Select
Isolation Mode: Sandbox and Storage: Database
19. Click
Register Selected Plugins
Register a Step on the Plugin
20. In
the left tree, expand (Assembly) MyCalcPlugin
21. Right-click
MyCalcPlugin.AddNumbers > Register New Step
22. Fill
in the step details as shown below:
|
Field |
Value |
|
Message |
new_AddNumbers (your action's unique name) |
|
Primary
Entity |
(leave
blank — unbound action) |
|
Event
Handler |
MyCalcPlugin.AddNumbers |
|
Eventing
Pipeline Stage |
Post-operation |
|
Execution
Mode |
Synchronous |
23. Click
Register New Step
|
Always right-click the plugin
class node to register a step. If you use the top toolbar instead, the Event
Handler dropdown will be blank and registration will fail. |
Step 6 — Call the Action from Power Automate
Now that everything is wired up,
you can call the action from a flow.
24. Create
a new flow in Power Automate
25. Add
a new action and search for Perform an unbound action (Dataverse connector)
26. In
the Action Name field, type your action's unique name: new_AddNumbers
27. The
input fields b and c will appear — map them to values or dynamic content
28. In
the next step, reference the output like this:
outputs('Perform_an_unbound_action')?['body/a']
|
If new_AddNumbers does not
appear in the dropdown, the action is still in Draft state. Go back to
make.powerapps.com and Activate it first. |
Common Errors and How to Fix Them
|
Error |
Fix |
|
Could
not load assembly System.Runtime Version=8.0.0.0 |
Wrong
target framework. Change project to .NET Framework 4.6.2 and rebuild. |
|
Assemblies
must be strongly signed |
Go to
project Properties > Signing tab, enable signing, create a .snk key file,
and rebuild. |
|
Strong
name validation failed (0x8013141A) |
Delete
bin\ and obj\ folders, clean solution, rebuild. Or run: sn.exe -Vr * |
|
Invalid
Message Name in PRT |
The
Custom Action has not been created in Dataverse yet. Create and activate the
action first. |
|
Plugin
was not specified (required field) |
You
used the top toolbar to register the step. Right-click the plugin class node
instead. |
|
No
values matching your search in Flow |
Action
is in Draft state or wrong unique name used. Activate the action and use the
prefix e.g. new_AddNumbers. |
How It All Fits Together
Here is a high-level view of the
full architecture:
C# Class Library (.NET
Framework 4.6.2)
|
| Build signed .dll
v
Plugin Registration Tool
|
| Register assembly + step on message
v
Dataverse Custom
Action (new_AddNumbers)
|
| Exposes as Web API endpoint
v
Power Automate ->
Perform an unbound action
|
v
Returns: a = b + c
Wrapping Up
To summarise what we covered:
•
Write a C# plugin targeting .NET Framework 4.6.2
•
Sign the assembly with a strong name key (.snk)
•
Create a Custom Action in Dataverse to define
input/output parameters
•
Register the plugin DLL and a step in the Plugin
Registration Tool
•
Call the action from Power Automate using the Perform
an unbound action connector
The diagram shows the full journey:
- C# Plugin — code + signing
- Plugin Registration Tool — deploy the DLL
- Dataverse Custom Action — the API contract
- Web API endpoint — what gets exposed
- Power Automate — where you consume it
Happy
coding!
No comments:
Post a Comment