Qualify a Lead in C#

Typically, when we want to deactivate a record in a plugin or a workflow, we turn to SetStateRequest. Qualifying a Lead isn't quite as straightforward. If you've qualified a Lead through the CRM interface, you'll know that:
  • An Opportunity is created from the originating Lead.
  • You can select whether to create a Contact or Account from the originating Lead.
QualifyLeadRequest in the Microsoft.Crm.Sdk.Messages namespace provides us with a class which allows us to specify all of these options and more programatically.

The code snippet below creates a new QualifyLeadRequest, populating all of it's required properties.

Replace all of my empty new EntityReference() objects with valid EntityReferences (which are instantiated by passing an entity name and an ID). Refer to the Microsoft documentation for information on other optional parameters which you can use.

The request is executed and its response stored in the qualifyLeadResponse:

The most interesting property of the response object is CreatedEntities. See the Microsoft documentation for information on other properties stored in the QualifyLeadResponse.

CreatedEntities contains a collection of EntityReferences, one for each entity created when qualifying the Lead. To get the Contact that was created, for example, iterate through the collection and query the LogicalName of each EntityReference:

Retrieve Option Set Metadata in C#

Given the name of an entity and the name of an option set field, Microsoft.Xrm.Sdk.Messages can retrieve all the labels and corresponding integer values for an option set.

Simply build a new RetrieveAttributeRequest and iterate over the response like so:

optionList now contains a list of all option set options where each object in the list has a Value property and a Text property.

To retrieve a given option set value for a label, use a Linq query:

Plugin Extensions: Shorten Your Code

There are some lines of code in plugins and workflows that I've written too many times.

1. Getting an attribute

Before we get an entity's attribute, we always check that the entity first contains the attribute. This is because attempting to access the value of an attribute that doesn't exist throws a NullReferenceException. Here's an example that gets the first name of a contact:

2. Initialising plugin variables

The following code gets the basic objects needed to run a decent plugin. Look how long-winded it is!

How to shorten things: write extension methods

Create a separate, static class called Extensions.cs. Note the namespace your class is in. If it's in a different namespace to your plugins, you must add a using statement at the top of your plugin classes.

Here's an example extension method that allows the simplification of 1. from above:

It can be used as follows. Note that we no longer need to check if an entity contains an attribute.

Here's an extension method that shortens the initialisation of plugin variables:

Here's how we can now initialise the same variables as shown in 2. from above:

Much cleaner!

TypeScript Development for CRM: Keep It Clean

More recently, applications built to integrate with CRM, either as external SPAs or HTML pages embedded within CRM, have utilised the TypeScript superset of JavaScript. If you're not already using TypeScript, see this great StackOverflow answer on why you should consider it (though this answer is general and not specific to Dynamics CRM development).

One annoyance many developers face when using TypeScript is file layout within the IDE. TypeScript compiles from .ts files to multiple .js files which can clutter file hierarchy layout on the IDE interface. This can be resolved in one of two ways.

1. Change your output directory

Navigate to your tsconfig.json file and specify an output directory that is different to the location of your .ts files. This could be /dist or /build:

2. Hide your .js files

Changing your output directory and moving your .js files can cause issues. For example an index.html page that references main.js will no longer work if you're now compiling to /dist/main.js. You may therefore consider whether you just want to hide your .js files from your IDE.

In Visual Studio Code, go to File > Preferences > Settings or your .vscode\settings.json file and enter:

To hide .js files one file directory deeper, add further lines to your .json file with an additional /*:

Before
With .js files
After
Without .js files

Finish a Business Process Flow in C#

When you create a business process flow you create a custom entity. For example, if you create a business process flow called Marketing Management in the default solution, you will create an entity called new_marketingmanagement. When you activate a business process flow on a record, an instance of that entity is created. The instance holds information such as which stage the process is at and when the process was started. You can deactivate the instance using Microsoft.Xrm.Sdk.Messages.SetStateRequest:

Where processFlowName is the logical name of your business process flow as a string and processId is the ID of the process flow instance you want to deactivate as a GUID.

To find the ID of your process flow instance, you can query the attribute _bpf_primary_key_value where primary_key should be replaced with the primary key of the entity which your process is on. For example on the Account entity this would read _bpf_accountid_value.

Finish a Business Process Flow in JavaScript

Often it's required that a business process flow is moved to its next stage via JavaScript. Less often it's required that the flow is marked as finished as well. Fortunately, an active business process flow can be set to finished using the Xrm namespace.

An important note is that although the Microsoft documentation says to pass finish as a parameter, you must pass finished. You can also pass active or abandoned.

Get Faults from an ExecuteMultipleRequest

If you have multiple entities to create or update in a plugin, it can be useful to package all entity create messages up into one bundle and send the request off at once. It is possible to see a performance benefit from this, but typically it's used to fulfill a business requirement. However, it can be trickier to establish if any errors have occurred. When only one request is sent, such as executing a create request for one new entity, typically the request is wrapped in a try/catch block.

Here's an example showing how to bundle multiple UpsertRequests into one ExecuteMultipleRequest:

requests can then be executed to return a list of responses, which can be iterated over. For each response in the iteration, we can determine if a fault occurred and if it did, add the error to a list of errors:

Notes:
  • response.RequestIndex is used to aaccess the response's corresponding request by matching their indexes.
  • responses.Responses contains a collection of ExecuteMultipleResponseItems.

Retrieve All Privileges for a Security Role

To retrieve all privileges for a security role, use RetrieveRolePrivilegesRoleRequest.

Replace securityRoleId with the ID of the security role you want to query and service with your IOrganizationService.

roleResponse.RolePrivileges will contain a long list of privilege IDs which are not very useful on their own. You can get the name of all of these privileges like this:

Now you will have all columns (attributes) for all privileges for a given security role stored in privileges

To go one step further, you can filter your privileges by the entity they refer to like so:

SDK.REST.updateRecord Gotcha

If you're using SDK.REST.updateRecord to update a record in CRM, ensure that the object you pass contains the minimum number of attributes needed. Poor practice would be to retrieve the entity record in its entirety and then update certain attributes. For example, the following code retrieves an entire entity with all of its attributes:

Subsequently updating properties of the record variable and calling SDK.REST.updateRecord will not just update the attributes you've set, but all attributes.

The code above changes the record's Name to "A new name". When updateRecord is called, all attributes are updated, even though all attributes except for Name are just being overwritten with what they already were. This is a nuisance because:
  • Workflows which trigger on update of a field will trigger unnecessarily.
  • An unwanted performance overhead is incurred.
  • The executing user may have permission to update the record's Name but not access to update fields which may be secured fields. The update will therefore fail.

JavaScript Callbacks

If you need to access the response from an asynchronous XMLHttpRequest, provide your request with a callback. The code below retrieves a Contact from CRM by its ID. In the success function, a callback is called, passing it the result from the request (which should be the Contact).

To make use of the result, create a function to call getContact, and evaluate its result:

The callback is called once the response is ready. Notice that the callback function is passed anonymously here as the second parameter of the call to getContact. It is advisable to write this anonymous function separately and give it a name.