Programming Microsoft Dynamics CRM 4.0: Plug-ins
- 12/15/2008
Plug-ins provide one of the most powerful customization points within Microsoft Dynamics CRM. As users work in the application, their actions cause Microsoft Dynamics CRM to trigger events that developers can use to execute custom business logic through the use of plug-ins. For example, you can register plug-ins to run business logic every time a user creates an account or deletes an activity. You can create plug-ins to run in response to a vast number of events, including plug-ins for custom entities. You can use plug-ins for a variety of features, such as synchronizing data to an external database, tracking changes in an audit log, or simply creating follow-up tasks for a newly created account.
Some of the tasks you can accomplish with plug-ins—such as populating fields with default values or specific field formatting—you can also accomplish with form JavaScript. Plug-ins have the advantage of running on the server, so you are guaranteed that these types of tasks will run even if the entity is created or updated from a bulk import or through the Web service API.
In this chapter, we will explore the following topics in detail:
Writing your first plug-in
The event execution pipeline
Details of the IPluginExecutionContext interface
Impersonation
Exception handling
Deploying plug-ins
Debugging plug-ins
Unit testing plug-ins
Real-world plug-in samples
Writing Your First Plug-in
When working with a new framework or technology, we find it easiest to start with a simple hands-on example and then dig deeper into real-world examples. We’ll start by implementing a simple plug-in to provide a more concrete foundation for the remainder of the chapter.
This plug-in verifies that an account’s accountnumber follows a specific format. In this example, Microsoft Dynamics CRM executes the plug-in when a new account is created or modified to verify that the account number starts with two letters followed by six numbers.
As mentioned earlier, you could accomplish this same type of account validation through scripting with the form’s onsave event. However, enforcing business logic on the form might not be ideal because modifications to the account number through workflow or through an external application would bypass the onsave event script and possibly allow an invalid account number format. By using a plug-in, we can guarantee that Microsoft Dynamics CRM enforces our business logic regardless of the method used to create the account.
Creating the Plug-in Project
Plug-ins are implemented as classes that implement a specific interface and are contained within a signed Microsoft .NET assembly. The assembly needs to target the Microsoft .NET runtime version 2.0, which can be accomplished by creating a class library in Microsoft Visual Studio 2008 targeting the .NET Framework 2.0, 3.0, or 3.5. However, installing Microsoft Dynamics CRM 4.0 only guarantees that Microsoft .NET Framework 3.0 is installed on the server. If you need assemblies included in the Microsoft .NET Framework 3.5, you have to install that version of the framework yourself. Before we can create our first plug-in, we need to create a class library project. Follow these steps to set up your first plug-in project.
Creating the plug-in project in Microsoft Visual Studio 2008
Open Microsoft Visual Studio 2008.
On the File Menu, select New and then click Project.
In the New Project dialog box, select the Other Project Types > Visual Studio Solutions type, and then select the Blank Solution template.
Type the name ProgrammingWithDynamicsCrm4 in the Name box. Click OK.
On the File Menu, select Add and then click New Project.
In the New Project dialog box, select the Visual C# project type targeting the .NET Framework 3.0 and then select the Class Library template.
Type the name ProgrammingWithDynamicsCrm4.Plugins in the Name box. Click OK.
Delete the default Class.cs file.
Right-click the ProgrammingWithDynamicsCrm4.Plugins project in Solution Explorer and then click Add Reference.
On the Browse tab, navigate to the CRM SDK’s bin folder and select microsoft.crm.sdk.dll and microsoft.crm.sdktypeproxy.dll. Click OK.
Right-click the ProgrammingWithDynamicsCrm4.Plugins project in Solution Explorer and then click Add Reference.
On the .NET tab, select System.Web.Services. Click OK.
Right-click the ProgrammingWithDynamicsCrm4.Plugins project in Solution Explorer and then click Properties.
On the Signing tab, select the Sign The Assembly box and then select <New...> from the list below it.
Type the key file name ProgrammingWithDynamicsCrm4.Plugins, and then clear the Protect My Key File With A Password check box. Click OK.
Close the project properties window.
Implementing the Plug-in Class
After setting up our project, we are ready to implement our first plug-in. Let’s start by adding a class to our newly created project.
Adding the AccountNumberValidator class
Right-click the ProgrammingWithDynamicsCrm4.Plugins project in Solution Explorer. Under Add, click Class.
Type AccountNumberValidator.cs in the Name box. Click Add.
Replace the generated code in the AccountNumberValidator class with the code displayed in Example 5-1.
Example 5-1. The AccountNumberValidator plug-in source code
using System; using Microsoft.Crm.Sdk; using System.Text.RegularExpressions; namespace ProgrammingWithDynamicsCrm4.Plugins { public class AccountNumberValidator: IPlugin { public void Execute(IPluginExecutionContext context) { DynamicEntity target = (DynamicEntity)context.InputParameters[ParameterName.Target]; if (target.Properties.Contains("accountnumber")) { string accountNumber = (string)target["accountnumber"]; Regex validFormat = new Regex("[A-Z]{2}-[0-9]{6}"); if (!validFormat.IsMatch(accountNumber)) { string message = "Account number does not follow the required format. " + "(AA-######)"; throw new InvalidPluginExecutionException(message); } } } } }
AccountNumberValidator, a very simple plug-in, extracts the target account as a DynamicEntity and validates that the accountnumber property follows a specific pattern (two capital letters followed by a dash and then six numbers). We know the target input parameter will be a DynamicEntity representing the account because we will be registering this plug-in with the Create and Update messages for the account entity.
Notice that the only requirement at the class level for a plug-in is that it must implement the Microsft.Crm.Sdk.IPlugin interface. IPlugin has only a single method, named Execute, which takes a single argument of type IPluginExecutionContext. We will be exploring the IPluginExecutionContext interface in detail—as well as how Microsoft Dynamics CRM 4.0 handles exceptions thrown by plug-ins—later in this chapter. For more information on the DynamicEntity class and its use, refer to Chapter 3.
Building the Registration Tool
Unlike for Workflows, form changes, and other customizations to Microsoft Dynamics CRM, no Web-based interface is included to register plug-ins. However, the Microsoft Dynamics CRM SDK includes two utilities to help you register plug-ins, and you can also register plug-ins using the API.
Later in the chapter we will explore using the API to write your own plug-in registration tools, but for this first example we will use one of the CRM SDK’s registration tools, PluginRegistration. PluginRegistration is a Windows desktop application that has an intuitive graphical user interface for registering plug-ins and configuring which messages cause the plug-in to execute. You can find the PluginRegistration tool in the Tools folder within the CRM SDK.
The Microsoft Dynamics CRM SDK distributes PluginRegistration as source code only, so you will need to compile it before you can run it. Follow the guidelines in the readme.doc included in the tools\PluginRegistration folder to compile the application. PluginRegistration is distributed as a Visual Studio 2005 project, but Visual Studio 2008 can automatically upgrade it without problems.
Deploying the Plug-in
After compiling our plug-in registration tool, we are ready to register our first plug-in. During registration you specify which messages for specific entities will cause the plug-in to execute. Depending on the message, you can specify additional filtering or request more information to be provided to your plug-in during execution.
When you register a plug-in, Microsoft Dynamics CRM offers you multiple registration properties:
Mode. A plug-in can execute either synchronously or asynchronously.
Stage. This option specifies whether the plug-in will respond to pre-events or post-events.
Deployment. A plug-in can execute only on the server, within the Outlook client, or both.
Messages. This option determines which Microsoft Dynamics CRM events should trigger your logic, such as Create, Update, and even Retrieve.
Entity. A plug-in can execute against most of the entities, including custom entities.
Rank. This option is an integer that specifies the order in which all plug-in steps should be executed.
Assembly Location. This option tells Microsoft Dynamics CRM whether the assemblies are stored in the database or on the Web server’s file system.
Images. You can pass attribute values from the record as either pre-images or post-images for certain message types.
You configure these plug-in properties when you register the plug-in with Microsoft Dynamics CRM.
Mode
Microsoft Dynamics CRM allows you to execute plug-ins synchronously or asynchronously. Asynchronous plug-ins are loaded into the Microsoft CRM Asynchronous Service and executed at some point after the main event processing is complete. Asynchronous plug-ins are ideal for handling situations that are not critical to complete immediately, such as audit logging. Because the plug-in executes asynchronously, it does not negatively affect the response time for an end user who initiates the core operation.
Stage
When you register a plug-in, you can configure the plug-in to run before or after the core operation takes place. A plug-in that executes before the core operation is referred to as a pre-event plug-in, while a plug-in that executes after the core operation is a post-event plug-in. Pre-event plug-ins are useful when you want to validate or alter data prior to submission. With post-event plug-ins, you can execute additional logic or integration after the data has been safely stored in the database.
Deployment
One of the great new features of Microsoft Dynamics CRM 4.0 is the ability to have your plug-in logic execute offline with the Outlook client, further extending your existing solution. You can choose to have the plug-in execute only against the server, run offline with the Outlook client, or both.
Remember that when a client goes offline and then returns online, any plug-in calls are executed after the data synchronizes with the server. If you choose to have your logic execute both with the server and offline, be prepared for Microsoft Dynamics CRM to execute your plug-in code twice.
For more information about developing offline solutions and using plug-ins offline, please refer to Chapter 10.
Messages
In the documentation, Microsoft Dynamics CRM 4.0 refers to server-based trigger events as messages. The Microsoft Dynamics CRM 4.0 SDK also supports all the events from Microsoft Dynamics CRM 3.0, such as Create, Update, Delete, and Merge. In addition, Microsoft Dynamics CRM 4.0 includes some new messages such as Route, Retrieve, and RetrieveMultiple.
See the “Supported Messages and Entities” section later in this chapter for more information about the available messages. You can also use the API to write code to see whether Microsoft Dynamics CRM supports a particular message.
Entities
Most system and all custom entities are available for plug-in execution. Please refer to the “Supported Messages and Entities” section for more information on the supported entities.
Rank
Rank merely denotes the order in which a plug-in should fire. Rank is simply an integer, and Microsoft Dynamics CRM starts with the plug-in with the lowest rank and then cycles through all available plug-ins. You should definitely consider the order of plug-ins, depending on the logic they perform.
Assembly Location
You can deploy plug-in assemblies to the database, to a folder on the Microsoft Dynamics CRM server, or to the Global Assembly Cache (GAC) on the server. Typically the database is the best option because you do not need to manually copy the file to the server before registering the plug-in. Unless you have a specific need to do otherwise, we recommend that you leave the default option and deploy your plug-ins to the database.
Images
Images provide you with the record attribute values. Images exist as pre-values (before the core plat form operation) and post-values. Not all messages allow images.
Now that you understand a little more background about the plug-in registration process, use the following steps to register the AccountNumberValidator plug-in.
Connecting to the server with the PluginRegistration tool
Launch the Plugin Registration tool that you compiled in the previous section. You will see the New Connection screen first (Figure 5-1).
Figure 5-1. The New Connection screen
Type any name you want for the Label. It is only used for display purposes in the PluginRegistration tool.
Type the name of your CRM server for the Discovery Server.
Optionally, specify the port your CRM server is running on if it is not port 80.
Optionally, specify the domain and user name you want to use to connect to the CRM server. If you specify a domain and user name, you will be prompted for a password when you connect. If you leave these fields blank, the tool connects as the currently logged on user.
Click Connect. You should now see a list of organizations under your connection.
Double-click the organization you want to register the plug-in with.
Now that you are connected to the server, next you will register the assembly on the server.
Registering the assembly
Select Register New Assembly from the Register toolbar drop-down list to open the Register New Assembly dialog box (Figure 5-2).
Figure 5-2. The Register New Assembly dialog box
Click the ellipsis button to browse and select the plug-in DLL. Note that the assembly and plug-in classes are selected by default in the selection tree.
Leave Database selected as the deployment location.
While you can deploy plug-ins to a folder or to the GAC on the Microsoft Dynamics CRM server, it is typically better to deploy to the database because you do not need to manually set up the assembly on the server. This point becomes even more valid if you are dealing with a web farm environment because you would need to copy the assembly to each server if you don’t specify database deployment.
Click Register Selected Plugins.
After this step you should see a series of messages in the Registration log. If all goes well, a confirmation dialog box will pop up to tell you that one assembly and one plug-in were registered.
Last you need to configure when the plug-in should run. You do this by registering steps with the PluginRegistration tool. Steps contain information such as the entity and message that will cause a plug-in to execute, as well as the stage it will execute in. Each plug-in can have multiple steps, allowing it to execute for different entities and messages.
Registering plug-in steps
Right-click the AccountNumberValidator plug-in in the Registered Plugins & Custom Workflow Activities tree, and then select Register New Step to open the Register New Step dialog box (Figure 5-3).
Figure 5-3. The Register New Step dialog box
Type Create in the Message box.
Type account in the Primary Entity box.
Specify accountnumber for the Filtering Attributes by clicking on the ellipsis button and then clearing all but the Account Number check box in the resulting dialog box.
Select the Pre Stage option.
Leave the rest of the settings at their default values.
Click Register New Step.
Repeat steps 1 through 7, but type Update in the Message box.
Now that you’ve registered the plug-in, it will verify that all newly created or modified account numbers match the specified format. If a user tries to create or update an account using an invalid account number, the error shown in Figure 5-4 appears. Likewise, if a workflow or service call tries to create or modify an account with an invalid account number, Microsoft Dynamics CRM will not update the account and will bubble up an exception to the caller.
Figure 5-4. An error presented to the user by the AccountNumberValidator plug-in