Showing posts with label Custom Workflow. Show all posts
Showing posts with label Custom Workflow. Show all posts

Retrieve Money Value from an an Aliased Value in a LinkEntity with C#

When you query an entity you can link another entity to it. You might want to do this to:
  • add additional conditions to your query with pertain to a related entity
  • return columns from two entities within only one query (which is more efficient)

Here's a scenario:

You have a Product lookup on the Lead entity titled 'Product of Interest' and the Product entity has an option set called 'Product Type'. A query could therefore be to retrieve all Leads that have a Product of Interest where the Product has a 'Product Type' of 'Equipment'.

In C#, your QueryExpression would utilise a LinkEntity and read as follows:

The query above retrieves all active Leads in CRM and links their Product of Interest, returning no columns from the Lead and the 'Price' column from the Product.

When retrieving the linked Product's 'Price' from a returned Lead, you might expect to be able to use GetAttributeValue, but unfortunately you can't. You must first use GetAttributeValue, then cast the object's Value property to Money, and then retrieve the Money's Value property... phew.

Here's the final code to retrieve a linked entity's Money value:

Note that the attribute you're retrieving from the Lead is "Product.price" not just "price". This is because LinkEntity attributes are prefixed with the EntityAlias property of the LinkEntity object passed to the QueryExpression (see the first code block above).

Calculate Working Time between Two Dates in C# (including SLA Working Hours)

Often we need to calculate the time between two dates, but only take into account working hours. Working hours usually fall somewhere between 09:00 - 17:00, Monday - Friday, and are defined in CRM via Entitlements and SLAs. There's no way to achieve this out of the box, therefore custom code must be written for this calculation within a plugin or a workflow.

The code I provide in this article is one of many ways this can be achieved. My approach here is to abstract days, minutes and time duration programatically and to then provide a static Calendar class to deal with CRM-specific logic.

Minute's are straightforward. You'll see here I simply conceptualise them as an object that has an Index property to represent which minute of the day the minute is. For example a minute with Index is 00:10.

One level higher, I outline a day, which has a list of minutes (there are 1440 minutes in a day):

Then we have a duration, which is a collection of days between a start and an end:

Finally we have a static calendar class which handles CRM-specific entitlement and SLA logic. This currently only works for retrieving an Entitlement from a Case. Attribute strings can be changed according to your requirement/the entity you're working with.

How is this used?

Firstly, the 4 classes from above are copied into a project.

Next, in the plugin's execute method, two DateTimes are retrieved, along with the context entity. In this example I'm using a Case entity and my Calendar class:

We now have a list of days representing a model of working hours defined in the Case's Entitlement stored in the workingHours variable.

We can now create a duration object, which models the time between our two DateTimes:

Then we remove time which we're not interested in (it falls outside of valid working hours):

And finally call GetTotalMinutes() and calculate the time in minutes between our two DateTimes without the invalid time:

And that's all. We now have the valid working time (in minutes) between the two DateTimes stored in the responseTime variable.

C# Attribute Checking is Inefficient

If an entity does not contain an attribute but we try to retrieve the attribute's value anyway, a NullReferenceException is thrown. Therefore, basic practice is to check that an entity contains an attribute before trying to retrieve the attribute's value. The following code snippet gets an account entity from a plugin's context then retrieves value for attribute address1_line1.

This is inefficient because .Contains() uses the same check as GetAttributeValue(), which internally refers to the actual entry location. The lookup functionality (finding the value of a key in a collection) is duplicated.

Use TryGetValue() instead

Last week I posted a set of useful extension methods to shorten our C# code, making it more readable and in some cases more efficient. Add a new extension method:

This method tries to get an attribute's value and returns true if the attribute exists. Crucially, it also returns the value of the attribute if it exists, as an out parameter.

We can now rewrite our code to get the value for address 1 line 1 and only iterate through the attribute collection once:


It's important to remember that this is a micro-optimisation. We should still consider whether slightly more optimised code is actually worth it i.e. does it sacrifice code readability?

This post was inspired by a recent pull request from the .NET Roslyn compiler which is open-source and hosted here on GitHub.

Finally, for the curious, the performance difference between TryGetValue and Contains is discussed further here on StackOverflow.

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!

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.