In This Chapter
A plug-in is a .NET assembly that can be used to intercept events generated from the CRM system to perform a variety of actions. An example of event interception is an entity that will be created, updated, or deleted; and an action can be almost anything. Some common plug-in uses include the following:
Performing a complicated update routine on CRM entities/attributes when it might be impractical to use JavaScript or business rules
Grabbing data from another system and updating CRM when an entity instance is being created or updated
Updating another system programmatically from CRM (such as an accounting system)
By using plug-ins, you can fire a custom action or event on any entity (for example, on the Account entity either before or after it is created, updated, or deleted). In addition, other events can be handled from a plug-in, such as Assign, Merge, and Handle. Refer to the Dynamics CRM software development kit (SDK) for a complete list of supported events. You can download the SDK from the Microsoft website; search for “Dynamics CRM SDK.”
Note
Not every event works in offline mode of the Microsoft CRM Outlook client. Whereas online mode supports all events, offline clients can manage only half of them. Refer to the CRM 2016 SDK for a complete list of events supported in offline mode, in the file called message-entity support for plug-ins.xlsx, which you can find in the SDK.
Figure 25.1 shows the event execution pipeline order in which the event and the plug-in calls are executed.
Tip
You don’t need to restart Internet Information Services (IIS) or any other CRM service when you register or unregister plug-ins.
Microsoft Dynamics CRM provides for registering plug-ins either in the sandbox (partial trust) or outside the sandbox (full trust). For Microsoft Dynamics CRM Online, plug-ins must be registered in the sandbox; On-Premises and Internet-Facing Deployment options can be registered in the sandbox or out of sandbox (or using the option none, which is out of the sandbox). CRM hosting providers might not support plug-ins without isolation mode for security reasons. Before you attempt to install a plug-in, check with your hosting provider to determine whether it allows you to use non-sandbox plug-ins. If a plug-in is registered in the sandbox in isolation mode, it will run in partial trust and won’t be allowed to access some resources on the server, such as files, the Registry, databases, and so on. This level of isolation, however, allows access to HTTP and HTTPS web resources for external web services communication. The sandbox allows a plug-in to access the CRM services to create, update, or delete any entity on the system.
Developing plug-ins in sandbox mode is the recommended action, because it makes them more secure and supported on all the CRM 2016 deployment types (Online and On-Premises). They are also monitored by the CRM system-generated runtime statistics that can be queried using the PluginTypeStatistic
entity records. If the sandbox worker process exceeds threshold CPU and memory limits and becomes unresponsive, the system kills it. In this case, currently executing plug-ins fail, but upon the next engagement, the plug-ins execute normally.
Finally, to deploy a plug-in without isolation mode, you need to add it as a deployment administrator, via the CRM Deployment Manager. Failure to do so results in failure to deploy the plug-in.
Tip
Being a deployment administrator is not required for deployment of sandbox plug-ins.
You can set up plug-ins in synchronous or asynchronous mode. Synchronous mode starts the execution of the plug-in when the event is fired and blocks the CRM application process until the executed method finishes. This option is not recommended if you are performing a process that might take a long time to execute. Regardless of the method used, synchronous or asynchronous, a timeout limit of 2 minutes applies for plug-in executions. If a process needs more time, you should consider using a workflow or another custom background process.
Tip
If you want to prevent another record from being created or updated, synchronous should be the desired mode, in conjunction with the pre-stage (see the next section, “Stages”).
Asynchronous mode releases the application process, and the user can continue working while the code is executed. You can check the execution status of asynchronous plug-ins from Settings > System Jobs. These plug-ins are executed by the Microsoft Dynamics CRM Asynchronous Processing Service, which is a Windows service.
Tip
The Microsoft Dynamics CRM Asynchronous Processing Service includes the following services:
Microsoft Dynamics CRM Asynchronous Processing Service (maintenance)
Microsoft Dynamics CRM Sandbox Processing Services
You can set up plug-in steps in the pre-stages (either pre-validation or pre-operation) or post-stages (post-operation):
Pre-Stage—This stage is divided into pre-validation and pre-operation and sends control to the plug-in before the real event is executed in the core system. For example, you might attach a plug-in to the Create event of the Account entity; your code would execute before the Account was actually created in the CRM system. With this method, you could prevent the account or the entity record from being created.
Post-Stage—This stage is executed after the real event has executed in the core system. So, following the example just described, your code would be executed only after the account record has been created.
Dynamics CRM 2016 allows these stages to participate in SQL transactions as well.
The concept of using transactions now allows the rollback of a plug-in operation. If you have two different plug-ins attached to the same message of an entity and the second plug-in fails, it can now roll back the successful operation performed by the first plug-in. This was not easily done with earlier versions of Dynamics CRM. You can check whether a plug-in is running in a transaction by checking the IsInTransaction
property of IPluginExecutionContext
. The stages 20 (pre-operation) and 40 (post-operation) are the ones that guarantee to be part of a transaction, whereas stage 10 (pre-validation) might not be part of it.
There are three deployment types for plug-ins:
Server—The plug-in executes on the server. Execution occurs when users use the web client or the Outlook Online client as well as when any workflow is executed.
Offline—The plug-in executes on the client user machine where Outlook is running. This is especially useful when you’re running the Outlook client in offline mode.
Both—The plug-in executes on the server and in the Outlook client in offline mode. Keep in mind that the plug-in is executed twice: once when Outlook is offline and again when it connects to the server.
Tip
To prevent a plug-in from executing twice because of synchronization, check the IsOfflinePlayback
property of IPluginExecutionContext
.
The deployment type you select depends on what you want to do. If you need to grab data from an external system and need to have the user connected to the Internet or the network, you should have the plug-in run only on the server side, and the Outlook client will not have network access in offline mode.
You should use a plug-in when you need to integrate Microsoft Dynamics CRM with a legacy system or when you want to extend or customize the original functionality or behaviors of Microsoft Dynamics CRM.
Plug-ins are the best choice for enforcing complex business rules of your business. You could use JavaScript events to add validation on the rules you want to enforce; however, those types of validations work only when CRM is used through the native interfaces (such as the web or Outlook client). If you remember that other applications can be interacting with the CRM system through the web services, service endpoints, and so on, the validations and rules enforcement will work always if you put them on plug-ins or business rules. Plug-ins run on the server side, whereas JavaScript validations run on the client side. It is a good practice to put the validation logic in one place on the server side; that way, you know the hardware and resources you can use. Clients have a lot of different setting configurations on their browsers, and in some cases they might cause your validations to not work properly.
For more information about business rules, refer to CHAPTER 22 “Customizing the System.”
Tip
Putting the business rules and validations on plug-ins doesn’t mean you do not need to add validations with JavaScript events. In most cases, it is good to have the validations in both places to avoid unnecessary server calls.
Note
CRM 2016 has come up with real-time (synchronous) workflows that enable power users to control through workflows business logic that used to be controlled through plug-ins. If you are planning to upgrade from CRM 2013/2015 to CRM 2016, you might want to move your business logic from plug-ins to real-time workflows.
To develop a plug-in, you must download the Microsoft Dynamics CRM 2016 SDK from the Microsoft website. You can find it at the Microsoft website by searching for “Dynamics CRM SDK.”
Download the MicrosoftDynamicsCRM2016SDK.exe file, save it, and execute it (it is a self-Eetracting cabinet file) by double-clicking the file and entering the directory where you want to extract the files (see Figure 25.2).
To create a plug-in, you must create a new class library project in Visual Studio, using .NET 4.5.2, by selecting File > New > Project. Then select Visual C# > Windows on the left and select Class Library in the middle. Enter a name for the project and select a location and a solution name if they don’t auto-populate when you enter the project name (see Figure 25.3).
This version of Microsoft Dynamics CRM 2016 is based on the .NET Framework 4.5.2, and you can use Visual Studio 2013/2015 to create class libraries. Although you can also create class library projects in a variety of languages, including Visual Basic .NET, the examples in this book use C#.
The project template creates a new public class by default. After you create the project, you must add to your project a reference to the Microsoft.Xrm.Sdk.dll file and a reference to Microsoft.Crm.Sdk.Proxy.dll. These dynamic link library (DLL) files are located inside the SDKin subfolder.
Tip
You can use NuGet to add the assemblies using the following command:
Install-Package Microsoft.CrmSdk.CoreAssemblies
For more information about NuGet, visit www.nuget.org/packages/Microsoft.CrmSdk.CoreAssemblies/.
To add these references, follow these steps:
1. Go to the Solution Explorer and right-click myPlugin > References (under the root Solution node of the tree). Select Add Reference, as shown in Figure 25.4.
3. Locate the SDKBin folder on your local drive and select both the Microsoft.Xrm.Sdk.dll and Microsoft.Crm.Sdk.Proxy.dll files (see Figure 25.5). (To select more than one file, hold down the Ctrl key while you click the files you want.)
4. Click Add and then click OK to add the references to your project. You can then see these files inside the References folder of your project in the Solution Explorer (see Figure 25.6).
5. Add the using
sentence to the Microsoft.Xrm.Sdk namespace and implement the IPlugin
interface, as shown in the following code (where you need to rename Class1
with the name of your plug-in):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
namespace myPlugIn
{
public class Class1 : IPlugin
{
}
}
You can implement more than one plug-in on the same assembly by using different classes, if you want to.
As with any other interface, you must explicitly implement methods. In the case of the IPlugin
interface, you must implement the Execute
method, as shown in the following code:
namespace myPlugIn
{
public class Class1 : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
throw new NotImplementedException();
}
}
}
Caution
Using early binding in plug-ins is not recommended as early binding produces a bigger assembly and can bring more challenges than late binding. To learn more about these options, refer to Chapter 23, “Web Services.”
The following sections explain the main classes.
IServiceProvider
The Execute
method of the IPlugin
interface has only one parameter, named serviceProvider, which is IServiceProvider
type. From this parameter, you can get the plug-in execution context by entering the following code:
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
This main parameter has a method, GetService
, that enables you to get other services from the service provider, such as the context of the organization and the context of the tracer service. This enables you to interact with the current CRM trace to add debugging information for the execution of your plug-in. to get an instance of the trace service, use the following code:
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext
inherits from IExecutionContext
, which is a more generic interface that is also implemented by other classes, such as the RemoteExecutionContext
class used for Windows Azure integrations.
IExecutionContext
From the IExecutionContext
object, you can query all the property values associated with the entity and event context where the method is being executed. This class contains the properties described in the following sections.
BusinessUnitId
The BusinessUnitId
property returns the GUID (global unique identifier) of the business unit of the user making the request. Notice that this is not the GUID of the entity’s record. To return the GUID of the entity’s record, you use the new property PrimaryEntityId
.
CorrelationId
The CorrelationId
property returns the GUID of the plug-in event instance. Every time the event fires, it generates a new GUID that can be read from this property.
You can use this property for tracking and logging purposes, especially when you have more than one plug-in attached to the same event, to see whether the codes execute for the same event pipeline.
Depth
The Depth
property returns the depth of the originated event. This property is of integer type and grows as the plug-in execution goes deeper, which can happen if your plug-in calls a web service to update another entity that also fires an event for another plug-in’s execution code. You might need to check the value of this property to prevent infinite loops if the web service calls a method that fires the same plug-in execution that might produce a deadlock. The maximum number for the Depth
property is set to 8
. A system administrator can increase this value by running the PowerShell command Set-CrmSetting
on the CRM server by changing the value of the WorkflowSettings.MaxDepth
setting.
InitiatingUserId
The InitiatingUserId
property returns the GUID of the user who initially invoked the operation.
InputParameters
The InputParameters
property is a collection of the request parameters associated with the event. You can use this property to retrieve the entity object for which the event is fired:
Entity entity = (Entity)context.InputParameters["Target"];
Tip
You may receive the following error when building a solution:
'System.Runtime.Serialization.IExtensibleDataObject' is defined in an assembly
that is not referenced.
To fix this, add a reference to the assembly System.Runtime.Serialization
.
The type of the target input parameter depends on the message. For example, the delete message returns an EntityReference
:
EntityReference entity = (EntityReference)context.InputParameters["Target"];
It is a good practice to verify the type of the target parameter, as follows:
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"]
is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
}
Also, you must make sure the entity contains the attribute you are looking for. The entity returned in the target parameter will contain only the attributes that were modified or created, and not all the entity fields. For example, the following code attempts to change the name of the Account entity:
if (entity.Attributes.Contains("name"))
{
entity.Attributes["name"] = "updated name";
}
else
{
entity.Attributes.Add("name", " new account name");
}
For example, if there is an update operation in the account record where the name was not changed, that field won’t be included in the target parameter. If for some reason you always need to know the value of this field, you can register an image for your plug-in. See the “Images” section, later in this chapter.
IsExecutingOffline
The IsExecutingOffline
property is used only for Outlook clients and returns whether the Outlook client is running in online or offline mode. This property is a Boolean type where true
= offline mode.
IsInTransaction
The IsInTransaction
property is used to determine whether the operation is participating in a SQL transaction. This property is a Boolean type where true
= is in transaction.
IsOfflinePlayback
The IsOfflinePlayback
property is used only for Outlook clients and returns whether the Outlook client is transitioning from offline to online mode. This property is a Boolean type where true
= synchronizing with the server.
IsolationMode
The IsolationMode
property returns the IsolationMode
mode in which the plug-in is running (none or sandbox). This parameter is an integer type where 0
= none and 2
= sandbox.
MessageName
The MessageName
property returns the name of the event that invoked the plug-in. It is a string. These are the supported messages for custom entities:
Assign
Create
Delete
GrantAccess
ModifyAccess
Retrieve
RetrieveMultiple
RetrieveSharesPrincipalsAndAccess
RevokeAccess
SetStateDynamicEntity
Update
System entities can support other system messages. Refer to the message-entity support for plug-ins.xlsx file in the CRM SDK for a complete list of System entity–supported messages.
Mode
The Mode
property returns the mode in which the plug-in is running. It can be synchronous or asynchronous. This parameter is an integer type where
0
= synchronous and 1
= asynchronous.
OperationCreatedOn
The OperationCreatedOn
property returns the datetime value of the SystemJob
created for execution of an asynchronous plug-in. This value is null
in the case of a synchronous plug-in.
OperationId
The OperationId
property returns the operation GUID when the plug-in is running in asynchronous mode and gives you the ID of the current system job. In synchronous mode, this value is always an empty GUID.
OrganizationId
The OrganizationId
property returns the organization GUID where the plug-in is running. Even though plug-ins are registered by organization ID, having this property helps if you have a generic plug-in that will be installed in different organizations and you need to perform different tasks, depending on the organization the plug-in is running. This way, you maintain only one Visual Studio solution and set of source code.
OrganizationName
The OrganizationName
property returns the name of the organization where the plug-in is running. With this attribute, you do not need to make an API call to get the organization name by giving the organization ID.
OutputParameters
OutputParameters
is the collection of properties returned by an event. A common output parameter is the GUID returned when an entity is created. Be careful when adding parameters on pre-stages because they could be overwritten after the system processes the core event. For example, suppose that you want to return the accountid
property that is created when a plug-in is attached to the Create event of the Account entity in the post-stage:
Guid myAccountID = (Guid)context.OutputParameters["id"];
OwningExtension
The OwningExtension
property returns the data associated with the SdkMessage ProcessingStep
or the service endpoint. This property type is an EntityReference
class from which you can get, for example, the description of the step that is running where you registered the plug-in.
ParentContext
The ParentContext
property returns the context of the parent pipeline operation, which may happen if the plug-in is registered in the pre- or post-operations. Sometime the plug-in requires another internal messages to be executed, and this property gives you the context of the parent execution.
PostEntityImages
The PostEntityImages
property contains the collection of the images with the properties’ names and values after the system executes the core operation.
Note
With PostEntityImages
, you need to specify the images and what properties you want to have in this collection when you register the plug-in.
PreEntityImages
The PreEntityImages
property contains the collection of the images with the properties and values before the system executes the core operation. This is very useful on post-stages to see what values the associated entity had before an update operation, for example.
Note
As with PostEntityImages
, you need to specify the images and what properties you want to have with this collection when you register the plug-in.
PrimaryEntityId
The PrimaryEntityId
property returns the GUID of the entity’s record where the operation is performed. If you are working with accounts or contacts, you should use the following code to get the entity record identifier:
Guid id = context.PrimaryEntityId;
PrimaryEntityName
The PrimaryEntityName
property gets the related primary entity name you specified when you registered the plug-in. This property is a type of string and returns the name of the associated entity—for example, Account, Contact, and so on.
RequestId
The RequestId
property gets the ID (GUID) of the event execution pipeline. It returns null
for synchronous operations.
SecondaryEntityName
The SecondaryEntityName
property gets the related secondary entity name if you specified one when registering the plug-in. This entity is commonly used in the Parent Account or Contact of the Account entity. This property is a type of string and returns the string None
if no secondary entity name is specified.
SharedVariables
The SharedVariables
property is used as a common repository to store properties that plug-ins will share. It is useful when you need to pass a parameter value from one plug-in to another that is being executed in the same event pipeline.
Stage
The Stage
property gets the stage at which the synchronous plug-in execution is registered. It can have any of the following values:
10
= pre-validation
20
= pre-operation
40
= post-operation
UserId
The UserId
property returns the GUID of the user who is executing the operation. Notice that if you impersonate the plug-in’s SDK message-processing step, as explained later in this chapter, this returns the user you configure there and not the user who originally initiated the operation, which you find in the InitiatedUserId
attribute.
IOrganizationServiceFactory
If you need to create an instance of the organization service, you can do it by using the IOrganizationServiceFactory
instance.
The service instance returned by IOrganizationServiceFactory
has the method CreateOrganizationService
, which is used get an instance of IOrganizationService
.
Here is an example of how to use IOrganizationService
and the CreateOrganizationService
method:
namespace myPlugIn
{
public class Class1 : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)
serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService
(context.UserId);
}
}
}
IOrganizationService
To use the CRM services, you need to get an instance of IOrganizationService
, which provides programmatic access to metadata and data for an organization.
The service instance returned by IOrganizationService
has the following methods:
Associate—Used to create a link between records.
Create—Used to create records.
Delete—Used to delete records.
Disassociate—Used to remove a link between records.
Execute—Used, for example, to execute Fetch queries.
Retrieve—Used to retrieve a record.
RetrieveMultiple—Used to retrieve more than one record.
Update—Used to update records.
For more information about how to use this service and its methods, refer to CHAPTER 23.
ITracingService
For debugging purposes, you can use tracing by getting an instance of ITracingService
. The service instance returned by IOrganizationService
has the method Trace
, which is used to add login information that you can then read when profiling a plug-in.
Here is an example of how to use ITracingService
and the Trace
method:
namespace myPlugIn
{
public class Class1 : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
ITracingService myTracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
try
{
// do your work
myTracingService.Trace("Plug-in execution starts");
}
catch (Exception ex)
{
myTracingService.Trace("Plug-in Exception: {0}", ex.ToString());
throw;
}
}
}
}
Before delving into the details about plug-in development, you should take a look at the deployment options so that you can easily follow the sample code included later in this chapter.
The first step in plug-in deployment involves registering your plug-in and signing the assembly with a strong name key file. A strong name key is necessary for security so that the assembly can be trusted to execute external code, such as when invoking a web service. To sign your assemblies, follow these steps:
1. In the Solution Explorer, right-click your project and select Properties (see Figure 25.7).
2. Go to the Signing tab and check the Sign the Assembly check box (see Figure 25.8).
3. Create a new strong name key file by selecting New from the drop-down, as shown in Figure 25.9.
4. Enter a name for the key file and, optionally (but recommended), enter a password to protect the strong name key (see Figure 25.10).
Tip
Be sure to give the password to any developer who will need to build this plug-in.
5. Click OK to close the dialog, and you see the newly created strong name key added to your project in the Solution Explorer (see Figure 25.11).
To deploy your plug-in, you need to register it. You can do this programmatically or using a tool that comes with the CRM SDK called the Plug-in Registration Tool. The Plug-in Registration Tool comes as an application and is located in the SDKToolsPluginRegistration folder.
You can also use the Plug-in Registration Tool to register Service Bus endpoints. These types of components are explained in detail in Chapter 24, “Azure Extensions.” The Plug-in Registration Tool is also used to register custom workflow activities, which are fully covered in Chapter 26, “Process Development.”
You can follow these steps to integrate the Plug-in Registration Tool into Visual Studio 2015 as a recommended option:
1. In Visual Studio 2015, select Tools > External Tools (see Figure 25.12). The External Tools dialog, shown in Figure 25.13, appears.
2. Click the Add button and change the title to CRM Plug-in Registration (see Figure 25.14).
3. Click the ellipsis ... button next to the Command field and locate the PluginRegistration.exe application file, which you should find in the SDKToolsPluginRegistration folder (see Figure 25.15).
4. Click Open to close the dialog and click OK to close the External Tools dialog. In addition, change the initial directory to the directory where you have the Plug-in Registration Tool.
You can now run the Plug-in Registration Tool from Visual Studio 2015 by selecting Tools > CRM Plug-in Registration (see Figure 25.16).
When you run the Plug-in Registration Tool, you must first click Create New Connection and select the deployment type, which can be either On-Premises or Office365 (used for CRM Online deployments). Then you need to enter information for the server name and port (typically 80 for HTTP and 443 for HTTP when using SSL) and the authentication source. You also need to check the Display List of Available Organizations check box, as shown in Figure 25.17.
The Plug-in Registration Tool has the option to use the credentials of the user you are already logged in as, so you don’t have to enter the username and password every time you run the tool. If you want to use a different user credential, you can uncheck the Use Default Credentials check box (refer to Figure 25.17) and enter a valid username, password, and domain.
Tip
The option to use the credentials of the user you are logged in as works only with On-Premises deployments.
The username and password must be valid Windows account credentials and for a valid Microsoft CRM user with administrative roles assigned, as well as deployment administrator rights that can be added through the CRM Deployment Manager. If the plug-in is going to be registered with the isolation mode set to Sandbox, the user doesn’t need to be a deployment administrator; in that case, the CRM system administrator role is enough.
After you enter these values, click Login to connect to the organization and then select the organization you want to connect with.
If you need to connect to another organization, you need to click Create New Connection again. Doing so does not disconnect you from the first organization you connected to before but does create another tab with the second organization name you selected (see Figure 25.18).
If you are connected successfully to the CRM organization, you see the Registered Plug-ins & Custom Workflow Activities page, as shown in Figure 25.18.
Follow these steps to complete the plug-in registration:
1. Build the Visual Studio solution project so you can register the generated DLL, and make sure to build the assembly signed with a strong key to avoid a build error. Then click the Register button and then click Register New Assembly. The Register New Assembly dialog, shown in Figure 25.19, opens.
2. Locate your assembly by clicking the ellipsis ... button near the top of the Register New Assembly dialog. Select Sandbox under Step 3. (Remember that the sandbox isolation mode is preferred when deploying to a CRM Online environment.) Select Database under Step 4 and be sure to select the class you want to register that appears on the list. Then click the Register Selected Plugins button. When the assembly is registered, a confirmation window appears, as shown in Figure 25.20.
3. Expand the assembly you registered to make sure your assembly was properly registered (see Figure 25.21).
4. Associate the assembly with an entity and an event by clicking the assembly you registered in the previous steps and selecting Register > Register New Step (see Figure 25.22).
5. To register a step (and select the entity and event), enter the message Create in the Message field and account in the Primary Entity field (see Figure 25.23).
Note
The Message and Primary Entity text boxes have IntelliSense, so you are presented with a list of values after you enter the first characters.
6. Select the Pre-Operation option from the Event Pipeline Stage of Execution list and leave the other radio buttons set to their default values, as shown in Figure 25.23.
Tip
You can add impersonation to the plug-in step execution by changing the Run in User’s Context field. By default, this value is set to the calling user, which is the user that is executing the operation (Create, Update, or Delete). However, in some cases, you need to do operations in your plug-in where the calling user might not have permissions. In such a case, you can either specify a different user with a higher role and privileges or use the CRM System user (an internal user), which has all the privileges. If you selected a different user, you can find out know who was the original user who fired the message by checking the value of the InitiatingUserId
field of IExecutionContext
.
While registering a plug-in, you can store configuration information, using the Secure Configuration and Unsecure Configuration boxes, shown in Figure 25.23. You can store data in any format you want. You can retrieve this information in plug-in code by using a plug-in constructor:
public myPlugin()
public myPlugin(string unsecure)
public myPlugin(string unsecure, string secure)
The first string parameter contains unsecure information, and the second one contains secure information. Secure configuration is not accessible in plug-ins executing in offline mode. Secure configuration is good for passing sensitive data, such as a connection string that contains a username and password.
7. Click Register New Step to close this dialog box, and you see the new step registered (see Figure 25.24).
As you saw in Figure 25.19, you can deploy an assembly to either the local hard disk or the database server or to the GAC (Global Assembly Cache). The database is the recommended option for production environments that might be deployed on different servers, such as a load-balanced deployment. This way you don’t need to deploy the assembly on every server. The local hard disk option is the recommended option for debugging purposes.
Be sure to properly debug and test your plug-in before implementing it to a production environment. If a plug-in has an error, users cannot create accounts if you attached the plug-in to the account Create event and the pre-stage (see Figure 25.25).
SEE the “Plug-in Debugging” SECTION, later in this chapter, for help on debugging.
Tip
With exceptions thrown in plug-ins registered as synchronous, the user gets a dialog about the error. With exceptions thrown in plug-ins registered in asynchronous mode, the exceptions are logged in the system jobs, which you can see by going to the CRM web application and selecting Settings > System Jobs.
When registering a plug-in on the Update
method, it is a best practice to filter or specify the fields for which you want the plug-in to be fired. For example, you might want the plug-in to be fired only if the Name field of the Account entity changes. If you don’t configure the filtering attributes, the plug-in will fire if other fields change, unnecessarily decreasing the performance of the CRM server.
Filter or specifying the fields for which you want the plug-in to be fired is something you can do when you create a new step for the Update
method (see Figure 25.26).
Images are useful for update operations; they help you determine the original value of a field before a user fired an update operation.
For example, if you want to compare the value of the Account Name field of the Account entity, instead of getting an instance of the IOrganizationServiceFactory
to create IOrganizationService
and perform a Retrieve
method (which junior CRM developers sometimes do), you can just configure this field on a pre-image and read it directly from there without doing any web service call that will decrease the performance of the server.
You need to create images by using the Plug-in Registration Tool. To to so navigate to Register New Image as shown in Figure 25.27.
In the Register New Image Dialog that appears, set Image Type to be Pre Image or Post Image, enter a name for the image, enter an entity alias, and, in the Parameters field, select the attributes or fields you want the image to contain (see Figure 25.28). Click the Register Image button, and you see the image inside the plug-in (see Figure 25.29).
To unregister a plug-in, you select the plug-in you want to delete, the Assembly node, and then click the Unregister button. The confirmation dialog shown in Figure 25.30 appears.
Click Yes to confirm the operation, and you see a success dialog, as shown in Figure 25.31.
The use of the Plug-in Registration Tool is necessary to register plug-ins only when you are developing them. When you are distributing a plug-in to a production environment (or to another client), you don’t need to use this tool because you can use solutions to deploy your plug-in for distribution t.
You can debug a plug-in in two ways. The first, as shown in Table 25.1, is by attaching the debugger to the host process. The second is by using Plug-in Profiler. It is recommended that you use either of these methods in a development environment because both methods use Visual Studio and will interrupt all user activity with the server if you attempt to enable debugging in a production environment.
Before trying either debugging method, you need to build your plug-in with debug mode and put the PDB (project database) file generated by the compiler in the following directory (assuming that you have the CRM server installed on C:Program FilesMicrosoft Dynamics CRM): C:Program FilesMicrosoft Dynamics CRMServerinassembly. This file is located in the output folder of your Visual Studio project, which is typically located at debugin.
Unfortunately, you must restart the IIS after copying the PDB file. You can do this via the command prompt by running the following command:
Iisreset
You can also restart the IIS by using a PowerShell command, like this:
Restart-Service W3SVC, WAS -force
Tip
You must copy the PDB file every time you rebuild the solution in Visual Studio and then restart the IIS.
Caution
You must have Visual Studio installed on the server where the CRM server is installed, or you can also install the Visual Studio 2015 Remote Debugger on the server and debug from a development workstation. The example in this section assumes that you have Visual Studio (2015 or later) installed on the same server where the CRM server is installed.
When you debug by attaching the debugger to the host process, you have to open your plug-in solution in Visual Studio 2015 first and put breakpoints where you want to stop and debug your code. To set a breakpoint, press F9 (see Figure 25.32).
You must attach the Visual Studio debugger to the w3wp.exe process, for example, to debug an online plug-in. To do that, select Debug > Attach to Process, as shown in Figure 25.33.
When the Attach to Process dialog appears, check the Show Processes from All Users check box and select the w3wp.exe process, as shown in Figure 25.34.
Note
If you can’t find the w3wp.exe process, it is probably because you need to first open an Internet Explorer window and browse to your CRM organization URL so that IIS will load the application pool represented by w3wp.exe.
You might also find that there is more than one instance of the w3wp.exe process running; this might depend on the number of different websites and application pools running on the same IIS. Because it is hard to say on which one your application is running, we recommend attaching to all the w3wp.exe instances.
If you are using the remote debugger, you must change the qualifier name to the name of the computer where the CRM and the remote debugger are installed.
If the plug-in has been registered with sandbox isolation mode, you must attach to another process instead of the w3wp.exe process. The process that hosts the plug-ins on a sandbox is called Microsoft.Crm.Sandbox.HostService.exe.
Click the Attach button to start debugging the plug-in.
Assuming that you registered the plug-in and associated it to the Account entity on the Create event (as in the earlier example in this chapter), when you go to the CRM web application and try to create a new account, you are automatically switched to the Visual Studio 2015 application (see Figure 25.35) after you click the Save or Save and Close buttons on the Account form.
If you need to debug CRM Online plug-ins or plug-ins in a production environment, you should use Plug-in Profiler. You can install Plug-in Profiler from the Plug-in Registration Tool. To do so, follow these steps:
1. Open the Plug-in Registration Tool, connect to your organization, and click the Install Profiler button (see Figure 25.36).
2. When the Plug-in Profiler is installed successfully, make sure it exists under the assemblies (see Figure 25.37).
3. Select the plug-in step that you want to debug, and you see the Start Profiling button available in addition to the Debug button (see Figure 25.38).
4. Click the Start Profiling button, and the Profiler Settings dialog appears (see Figure 25.39). These profiling settings are good for most scenarios. Click OK.
5. Perform the steps in CRM so that the plug-in step you are profiling gets executed. The Business Process Error dialog box appears (see Figure 25.40).
6. Click the Download Log File button to save the ErrorDetails.txt file on your computer. This log file contains the profile that the Plug-in Profiler will use to play back execution. Open the plug-in solution in Visual Studio and go to Debug > Attach Process and select PluginRegistration.exe (see Figure 25.41). Set a breakpoint in the plug-in code.
7. Go back to the Plug-in Registration Tool and click the Reply Plug-in Execution button that is on the command bar or select the step you are profiling and click Debug. Select ErrorDetails.txt for the profile location (Step 1) and select the debug version of the plug-in assembly for the assembly location (Step 2) (see Figure 25.42).
You can optionally click the down arrow to download the profile execution log from the server (see Figure 25.43). You will have files there if you previously selected Persist to Entity in the profile settings when you started the Plug-in Profiler.
8. Click Start Execution, and debugging starts in Visual Studio.
The SDK comes with some plug-in samples:
AccountNumberPlugin—This sample creates a random account number when an account is created.
FollowupPlugin—This sample creates a Task activity when an account is created.
PreEventPlugin—This sample demonstrates the use of shared variables to send data through different plug-ins.
WebClientPlugin—This sample shows how to access a network resource in a sandboxed plug-in.
AdvancedPlugin—This sample shows how to use pre- and post-images, tracing, how to pass secure and unsecure information, and so on.
You can find the code for these samples in C#, within the SDK, in the sdksamplecodecsplug-ins folder.
You can download the SDK from the Microsoft website; search for “Dynamics CRM SDK.”
Because Microsoft often updates the SDK, it is a good idea to check the download site for updated versions.
When you develop a plug-in, you register it by using the Plug-in Registration Tool, as explained earlier in this chapter. When you are done with the development and ready to distribute the plug-in, you can do so by creating a solution. Make sure you include the plug-in assembly and the SDK message processing steps in your solution (see Figure 25.44).
To learn more about working with solutions in Dynamics CRM 2016, refer to CHAPTER 22, “Customizing the System.”
When importing your plug-in solution to another CRM organization, make sure you check the check box Enable Any SDK Message Processing Steps Included in the Solution, or your plug-in won’t work (see Figure 25.45).
Caution
Be careful if you change the managed properties of the SDK message processing steps to false
. If a user who imports your solution unchecks the Any SDK Message Processing Steps Included in the Solution when importing the solution, the only way to enable the steps is by using the Plug-in Registration Tool because the message steps don’t show up in the installed solution.
Be careful about using secured configurations in the plug-in SDK message processing steps registration. The secure configuration is encrypted with a specific organization key and might be different from one organization to another. You might need to update this secure configuration manually for each environment where you install your plug-in solution.
In this chapter, you have learned about plug-ins—what they are and when it is recommended to use them. You have created a basic plug-in and reviewed all the development properties of the IServiceProvider
, IExecutionContext
, and IPluginExecutionContext
interfaces. You have learned how to deploy and register plug-ins by using the Plug-in Registration Tool within the UI. You have also learned how to test and debug plug-ins in two ways: by attaching the debugger to the w3wp.exe process and by using the Plug-in Profiler. Finally, you have learned how to distribute your plug-ins to other Dynamics CRM organizations using solutions.