Register a plug-in
The process of writing, registering, and debugging a plug-in is:
- Create a .NET Framework Class library project in Visual Studio
- Add the
Microsoft.CrmSdk.CoreAssembliesNuGet package to the project
- Implement the IPlugin interface on classes that will be registered as steps.
- Add your code to the Execute method required by the interface
- Get references to services you need
- Add your business logic
- Sign & build the assembly
- Test the assembly
- Register the assembly in a test environment
- Add your registered assembly and steps to an unmanaged solution
- Test the behavior of the assembly
- Verify expected trace logs are written
- Debug the assembly as needed
Content in this topic describes the steps in bold above and supports the following tutorials:
Plugin registration tool (PRT)
You will use the Plugin Registration Tool (PRT) to register your plug-in assemblies and steps.
PRT is one of the tools available for download from NuGet. Follow the instructions in Download tools from NuGet. That topic includes instructions to use a PowerShell script to download the latest tools from NuGet.
Register an assembly
Registering an assembly is the process of uploading the assembly to the Common Data Service database. See the instructions found at Register your assembly in the Tutorial: Write and register a plug-in
You will find options related to the isolation mode and location for the assembly. These refer to options that apply to on-premise deployments. Common Data Service is not available for on-premises deployments, so you will always accept the default options of SandBox and Database for these options.
When an assembly is uploaded it is stored in the
PluginAssembly entity. Most of the properties are set using reflection of the imported entity. The base64 encoded bytes of the assembly is stored in the
Content attribute. While viewing the Properties of the assembly in the PRT, you can only edit the Description attribute value.
View registered assemblies
You can view information about registered assemblies in the application solution explorer without using the PRT.
Navigate to an unmanaged solution
From the Power Apps portal select Solutions, and then on the toolbar, select Switch to classic.
In the All Solutions list select the unmanaged solution you want.
Each assembly you add using PRT will be added to the system Default Solution, (not to be confused with the Common Data Serices Default Solution). To view the Default Solution, select All solutions under Solutions and then change the view to All Solutions - Internal.
For more information about solutions, see Introduction to solutions
After selecting the name of the Default Solution in the internal solution list, you can find all the assemblies that are registered for this environment.
Query registered assemblies with code
To view information about registered assemblies without the PRT or the application, use the following Web API query in your browser:
[org uri]]/api/data/v9.0/pluginassemblies ?$filter=ishidden/Value eq false &$select= createdon, culture, customizationlevel, description, isolationmode, major, minor, modifiedon, name, pluginassemblyid, publickeytoken, version
Or use following FetchXml to retrieve it in a program you write:
<fetch> <entity name='pluginassembly' > <attribute name='createdon' /> <attribute name='culture' /> <attribute name='customizationlevel' /> <attribute name='description' /> <attribute name='isolationmode' /> <attribute name='major' /> <attribute name='minor' /> <attribute name='modifiedon' /> <attribute name='name' /> <attribute name='pluginassemblyid' /> <attribute name='publickeytoken' /> <attribute name='version' /> <filter type='and' > <filter> <condition attribute='ishidden' operator='eq' value='false' /> </filter> </filter> </entity> </fetch>
More information: Use FetchXML with FetchExpression
Add your assembly to a solution
As described in View registered assemblies, the assembly registration you created was added to the system Default Solution. You should add your assembly to an unmanaged solution so you can distribute it to other organizations.
Within the unmanaged solution you are using, use solution explorer to navigate to Plug-in Assemblies. In the list menu, select Add Existing. Note that in the following figures, a custom solution named Common Data Service Default Solution is used.
Then add your assembly as a component to the solution.
When you select the plug-in assembly you added, you can view the plug-in classes it includes.
Any existing or subsequent step registrations are not added to the unmanaged solution that includes the plug-in assemblies. You must add each registered step to the solution separately. More information: Add step to solution
Register plug-in step
When an assembly is loaded or updated, any classes that implement IPlugin will be available in the PRT. Use the instructions in Register a new step in the Tutorial: Write and register a plug-in to create a new step registration.
When you register a step, there are many options available to you which depend on the stage of the event pipeline and the nature of the operation you will register your code to respond to.
General Configuration Information Fields
|Message||PRT will auto-complete available message names in the system. More information: Use messages with the Organization service|
|Primary Entity||PRT will auto-complete valid entities that apply to the selected message. These messages have a
If you leave it blank for core entity messages like
|Secondary Entity||This field remains for backward compatibility for deprecated messages that accepted an array of EntityReference as the
|Filtering Attributes||With the
|Event Handler||This value will be populated based on the name of the assembly and the plug-in class.|
|Step Name||The name of the step. A value is pre-populated based on the configuration of the step, but this value can be overridden.|
|Run in User's Context||Provides options for applying impersonation for the step. The default value is Calling User. If the calling user doesn't have privileges to perform operations in the step, you may need to set this to a user who has these privileges. More information: Impersonate a user|
|Execution Order||Multiple steps can be registered for the same stage of the same message. The number in this field determines the order in which they will be applied from lowest to highest.
Note: You should set this to control the order in which plug-ins are applied in the stage. It not recommended to simply accept the default value. If all plug-ins for the same stage, entity, and message have the same value, the SdkMessageProcessingStep.SdkMessageFilterId value will determine the order in which they are executed.
|Description||A description for step. This value is pre-populated but can be overwritten.|
Event Pipeline Stage of execution
Choose the stage in the event pipeline that best suites the purpose for your plug-in.
|PreValidation||For the initial operation, this stage will occur before the main system operation.
This provides an opportunity to include logic to cancel the operation before the database transaction.
Subsequent operations triggered by extensions registered in other stages will pass through this stage as well but will be included within the transaction of the calling extensions.
This stage occurs before any security checks are preformed to verify that the calling or logged-on user has the correct permission to perform the intended operation.
|PreOperation||Occurs before the main system operation and within the database transaction.
If you want to change any values for an entity included in the message, you should do it here.
Avoid cancelling an operation here. Canceling will trigger a rollback of the transaction and have significant performance impact.
|PostOperation||Occurs after the main system operation and within the database transaction.
Use this stage to modify any properties of the message before it is returned to the caller.
Avoid applying changes to an entity included in the message because this will trigger a new Update event.
More information: Event execution pipeline
There are two modes of execution asynchronous, and synchronous.
|Asynchronous||The execution context and the definition of the business logic to apply is moved to system job which will execute after the operation completes.|
|Synchronous||Plug-ins execute immediately according to the stage of execution and execution order. The entire operation will wait until they complete.|
Asynchronous plug-ins can only be registered for the PostOperation stage. For more information about how system jobs work, see Asynchronous service
Special step registration scenarios
There are certain scenarios where step registration for a message and entity combination is not obvious. This is the result of how the system is designed internally where there is a special relationship between entities or operations. The information below identifies these cases and provides step registration guidance.
- There are certain cases where plug-ins registered for the Update event can be called twice. More information: Behavior of specialized update operations
- Register a plug-in step on account or contact when you want to handle data changes to customeraddress, leadaddress, publisheraddress, or competitoraddress entity instances.
|Server||The plug-in will run on the Common Data Service server.|
|Offline||The plug-in will run within the Dynamics 365 for Outlook client when the user is in offline mode.|
Set configuration data
The Unsecure Configuration and Secure Configuration fields allow you to specify configuration data to pass to the plug-in for a specific step.
You can write your plug-in to accept string values in the constructor to use this data to control how the plug-in should work for the step. More information: Pass configuration data to your plug-in
Define entity images
Within your plug-in, you may want to reference primary entity property values that were not included in an operation. For example, in an
Update operation you might want to know what a value was before it was changed, but the execution context doesn't provide this information, it only includes the changed value.
If your plug-in step is registered in the PreValidation or PreOperation stages of the execution pipeline, you could use the organization service to retrieve the current value of the property, but this is not a good practice for performance. A better practice is to define a pre entity image with your plug-in step registration. This will capture a 'snapshot' of the entity with the fields you are interested in as they existed before the operation that you can use to compare with the changed values.
Messages that support entity images
In Common Data Service, only the following messages support entity images:
|Message||Request Class Property||Description|
||The assigned entity.|
||The created entity.|
||The deleted entity.|
||The delivered email ID.|
||The delivered email ID.|
||The parent entity, into which the data from the child entity is being merged or the child entity that is being merged into the parent entity.|
||The item being routed.|
||The item being sent.|
||The entity for which the state is set.|
||The updated entity.|
Types of entity images
There are two types of entity images: Pre Image and Post Image. When you configure them, these images will be available within the execution context as PreEntityImages and PostEntityImages properties respectively. As the names suggest, these snapshots represent what the entity looks like before the operation and after the operation. When you configure an entity image, you will define an entity alias value that will be the key value you will use to access a specific entity image from the
Availability of images
When you configure an entity image it is important that you recognize that the type of entity images available depend on the stage of the registered step and the type of operation. For example:
- You cannot have a Pre Image for the
Createmessage because the entity doesn't exist yet.
- You cannot have a Post Image for the
Deletemessage because the entity won't exist anymore.
- You can only have a Post Image for steps registered in the PostOperation stage of the execution pipeline because there is no way to know what the entity properties will be until the transaction is completed.
- For an
Updateoperation that is registered in the PostOperation stage you can have both a Pre Image AND a Post Image.
Add an entity image
Add step to solution
As mentioned in Add your assembly to a solution, Plug-in Assemblies are solution components that can be added to an unmanaged solution. Sdk Message Processing Steps are also solution components and must also be added to an unmanaged solution in order to be distributed.
The procedure to add a step to a solution is similar to adding an assembly. You will use the Add Existing command to move it into the desired unmanaged solution. The only difference is that if you attempt to add a step but have not already added the assembly that contains the class used in the step, you will be prompted to add missing required components.
If you encounter this, you should usually select OK to bring the assembly in with the unmanaged solution. The only time you would not select this is if your solution is designed to be installed in an environement where another solution containing the assembly is already installed.
Similarly, you should note that removing the assembly from the solution will not remove any steps that depend on it.
Update an assembly
When you change and re-build an assembly that you have previously registered, you will need to update it. See the Update the plug-in assembly registration step in the Tutorial: Update a plug-in for the steps.
If you are making changes to a plug-in assembly that is part of a managed solution that has been deployed you need to consider the impact your changes may have when you update that managed solution. The version of the assembly will control the behavior.
Plug-in assemblies can be versioned using a semantic versioning format of
major.minor.build.revision defined in the
Assembly.info file of the Microsoft Visual Studio project. Depending on what part of the assembly version number is changed in a newer solution, the following behavior applies when an existing solution is updated through import.
The build or revision assembly version number is changed
This is considered an in-place upgrade. The older version of the assembly is removed when the solution containing the updated assembly is imported. Any pre-existing steps from the older solution are automatically changed to refer to the newer version of the assembly.
The major or minor assembly version number is changed
When an updated solution containing the revised assembly is imported, the assembly is considered a completely different assembly than the previous version of that assembly in the existing solution. Plug-in registration steps in the existing solution will continue to refer to the previous version of the assembly. If you want existing plug-in registration steps for the previous assembly to point to the revised assembly, you will need to use the Plug-in Registration tool to manually change the step configuration to refer to the revised assembly type. This should be done before exporting the updated assembly into a solution for later import.
Unregister or disable plug-in components
You can unregister or disable plug-in components.
You can also delete Plug-in Assemblies and Sdk Message Processing Steps in the solution explorer to achieve the same result. In the figure below, a custom solution named Common Data Service Default Solution is shown.
You cannot delete any Plug-in Assemblies while existing Sdk Message Processing Steps depend on them. Entity images are not available to be deleted separately, but they will be deleted when any steps that use them are deleted.
The PRT provides commands to disable and enable steps.
You can also disable steps in the solution explorer using the Activate and Deactivate commands.