Introduction
A plug-in is .Net assembly that can be used to intercept events generated from the CRM system. Plug-ins subscribe to a set of events and run when the events occur regardless of how the event raised (or the method that is used to perform the activity that raised the event).
Any number of plug-ins can be associated with a given entity and event. When multiple plug-ins are registered for the same event on the same entity, they are called in a sequence based on the order specified on the step registration. This value is specified as the Rank and it is supplied when the plug-in is registered. This allows developer control over the sequence.
Common Uses of Plug-ins
Plug-ins have many uses like:
Plug-ins Basics
Event Framework Event framework is the term that is used to describe the technology and mechanisms available in Microsoft Dynamics CRM to enable you to extend or customize functionality with custom code. Your custom code will run on top of Dynamics CRM either synchronously as part of the main Microsoft Dynamics CRM execution path, or asynchronously from a managed queue.
Event Execution Pipeline Event framework executes plug-ins based on a message pipeline execution model. A user action in the Microsoft Dynamics CRM Web application or an SDK method call by a plug-in or other application results in a message being sent to the organization Web service. The message contains business entity information and core operation information. The message is passed through the event execution pipeline where it can be read or modified by the platform core operation and any registered plug-ins.
The event execution pipeline processes events either synchronously or asynchronously. The platform core operation and any plug-ins registered for synchronous execution are executed immediately. Synchronous plug-ins that are registered for the event are executed in a well-defined order. Plug-ins registered for asynchronous execution are queued by the Asynchronous Queue Agent and executed at a later time by the asynchronous service.
Pipeline Stages The event execution pipeline is divided into multiple stages, four of them are available to register custom developed plug-ins. Multiple plug-ins that are registered in each stage can be further be ordered (ranked) within that stage during plug-in registration.
Message Processing as we saw in a previous post, any web service method call is done through OrganizationRequest message. This call raises an event. Information in this message is passed to first plug-in registered for that event. Plug-in receives the message information in the form of context that is passed to its Execute method, where it can be read or modify its contents before passing it to the next registered plug-in for that event and so on. The message then passed to the platform core operation. After the core platform operation has completed, the message is then known as the OrganizationResponse. This response is passed to the registered post-event plug-ins which may modify it before a copy of the response is passed to any registered asynchronous plug-ins. Finally, the response is returned to the application or workflow that initiated the original Web service method call.
Because a single Microsoft Dynamics CRM server can host more than one organization, the execution pipeline is organization specific. Plug-ins registered with the pipeline can only process business data for a single organization.
Inclusion in Database Transactions Plug-ins can execute or not execute within the database transaction of the Dynamics CRM platform. Within the plug-in, you can detect that through the IsInTransaction property in IPluginExecutionContext that is passed to the plug-in. Any registered plug-in that executes during the database transaction and that passes an exception back to the platform cancels the core operation. This results in a rollback of the core operation. In addition, any pre-event or post event registered plug-ins that have not yet executed and any workflow that is triggered by the same event that the plug-in was registered for will not execute.
Plug-in Isolation The execution of plug-ins can be in an isolated environment, known as a sandbox, where a plug-in can access and use the organization Web service only. Plug-ins can’t access system resources but can access to external endpoints (only through HTTP and HTTPS). CRM platform collects run-time statistics and monitors plug-ins that execute in the sandbox, if it exceeded certain thresholds or became unresponsive, it kills the sandbox worker process (this makes all currently executing plug-ins in the current organization fail).
Trusts
Develop Plug-ins
Simply plug-ins are classes that implement the IPlugin interface. You can write a plug-in in any .NET Framework 4 CLR-compliant language.
Now let’s consider a simple case that plug-ins may be its appropriate solution. Let say that your company wants leads to be numbered automatically when they are created. In order to achieve our goal, we will add a custom field to the Lead entity and add it to the form. We will disable this field on the form. We will create a plug-in and register it for the Pre-event for the Create message on the Lead entity. When a lead is created, it will look for the next available number in the system and assign it to the newly created Lead.
Step 1: Create Customizations
Now we will quickly customize the Lead entity and form to accommodate
our solution. Navigate to Settings >
Customizations > Customize the System. In the left navigation
pane, expand Entities, expand Lead, select Fields, and click New.
In the New for Lead form, set the Display Name to Auto Number, the Type
to Whole Number, and then click Save and
Close. In the left navigation Pane, select Forms. Click the Main Information form >
Drag the field, new_autonumber, to the Name section of the General section. Select the field, click Change Properties, mark the Field is read-only check box, and then click
OK. Click Save
and Close, and then Publish.
Step 2: Create the Plug-in
1- Open Visual Studio and Create a new project of type Class Library.
2- Add references to Microsoft.Xrm.Client.dll, Microsoft.Xrm.Sdk.dll, and Microsoft.crm.sdk.proxy.dll [located at %SDK%\bin folder].
3- Add references to System.Data.Services, System.Data.Services.Client, System.Runtime.Serialization, and System.ServiceModel.
4- Add reference to Microsoft.IdentityModel.dll from “C:\Program Files\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\”. Then go to reference properties and set Copy Local to True for the DLL. The DLL will be included in the package. If you don’t have the dll you need to install Windows Identity Foundation.
5- Make your class implement the IPlugin interface, and implement its member method Execute method. This identifies your class as a plugin to the CRM platform when registering your assembly later. Plug-in code will be placed in the Execute method which takes a parameter of type IServiceProvider. This parameter is a container of many objects that will be utilized by our code.
First get the IPluginExecutionContext. This context object gives you access to all the property values associated with the entity and event context where the method is being executed.
IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext));
InputParameters property of the context is a collection of the request parameters associated with the event. We use it to check the entity of which the event is fired.
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "lead")
return;
Then we get the OrganizationServiceFactory to use it to create an OrganizationService. We also get the TracingService. Then we edited our auto number field with the next maximum number in the organization. GetMaxLeadNumber is a typical method that passes a QueryExpression to the OrganizationService to get the next max lead number.
IOrganizationServiceFactory orgServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IOrganizationService orgService = orgServiceFactory.CreateOrganizationService(context.UserId);
try
{
entity.Attributes["new_autonumber"] = GetMaxLeadNumber(orgService);
}
catch (Exception ex)
{
tracingService.Trace("xRM_Demo03 | {0}", ex.ToString());
throw;
}
}
}
Now your class should look like:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Security;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using System.Collections;
namespace xRM_Demo03
{
public class Plugin:IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "lead")
return;
IOrganizationServiceFactory orgServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService orgService = orgServiceFactory.CreateOrganizationService(context.UserId);
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
try
{
Random rand = new Random();
entity.Attributes["new_autonumber"] = GetMaxLeadNumber(orgService);
}
catch (Exception ex)
{
tracingService.Trace("xRM_Demo03 | {0}", ex.ToString());
throw;
}
}
}
private int GetMaxLeadNumber(IOrganizationService orgService)
{
QueryExpression qe = new QueryExpression("lead");
qe.ColumnSet.AddColumn("new_autonumber");
qe.AddOrder("new_autonumber", OrderType.Descending);
qe.PageInfo.Count = 1;
qe.PageInfo.PageNumber = 1;
Entity entity = (Entity)orgService.RetrieveMultiple(qe)[0];
if (entity.Attributes["new_autonumber"].ToString()!= string.Empty)
return int.Parse(entity.Attributes["new_autonumber"].ToString()) + 1;
else
return 1;
}
}
}
Now the last step is to sign your assembly. Double click Properties under your plugin project.
then click Signing from the left tabs
select Sign the assembly checkbox, choose New from the dropbox or choose an existing key. Build the project. Now we are ready to register our plugin into Dynamics CRM.
Step 3: Register the Plug-in
The Dynamics CRM SDK have a tool to register plugins located as a source code at %CRMSDK%\tools\pluginregistration. Open the solution, build it, and run it.
1- Click the Create New Connection on the toolbar. Enter a name for the connection, organization URL, and the email you used for creating this organization.
Click Connect, it will ask you for the password.
Enter your password and click Ok to connect to the CRM organization web service.
After getting connected click Register > Register New Assembly
This will open Register New Plugin dialog.
Click the three dots button in the top right of the dialog, browse to your plugin dll. Ensure that your plugin is listed and checked. Also ensure that you selected Sandbox as isolation mode, and to store your assembly in the Database as shown below.
Click Register Selected Plugins. You will see in the log the steps done by the tool and when it is done it will show message box showing how many assemblies and plugins have been registered (you could have multiple plugins in one assembly). Click Ok.
Now select your assembly from the list
and click Register > Register New Step. This will open Register New Step dialog. This dialog used to define mainly the message, the entity, and the stage that your plugin will execute within. We will register for Message Create, Entity lead, Pre-operaton stage. Click Register New Step.
You will see child step added under your assembly.
Now our assembly is registered and our plugin will run for create messages on the lead entity. Go to the CRM web interface and create a new lead, save it, open it again and see the Auto Number populated.
In this post we explored the plug-in basics, and developed a simple plug-in. To complete the picture, you also explored how to register our plug-in into Dynamics CRM and see it in action.