Dealing with Multi-Language Lookups

Very often, CRM entities are used as reference data tables, for example to keep a list of countries, states or provinces or other business/industry specific data. For some businesses I have seen entities to keep a list of distributors, list of business roles, regions to only name a few. When used that way, CRM entities provide a lot of great features that cannot easily be met with option sets such as the ability to manage large reference tables, lookup search, lookup filtering, ease of adding/editing/modifying data by power users without a deployment.

One of the issues with using CRM entities for reference data is that they is no concept of multi-language lookup in the Dynamics 365 / CRM platform. Lookups will always display the value of the primary field by default. This can cause an issue in places where you must have a fully multilingual application. In this article, I provide a few possible solutions to solve this issue.

As an example, we’ll use the context of a task for which we need to track its type. The list of the available task activity types is stored as records in an entity called “Task Activity“. The Task entity has a lookup to the Task Activity entity. The information needs to be stored in English and French


1 – Task Form with Lookup to Task Activity


2 – List of Task Activities

Resolution Option 1 – Concatenate multiple languages in one field with a separator

You will be disappointed, this is not a fancy solution. In the Task Activity entity, we have one field for the name in both languages and use concatenate both field values in the primary field using a workflow or plugin.

  • Name English (Single line of text – 100)
  • Name French (Single line of text – 100)
  • Name (Single line of text – 203) – read only for users, populated with “Name English | French Name”


3 – Task Activity Form

This is the most common approach that I have seen when the number of languages is small (2 languages). This has a disadvantage of sometimes creating long name values that are not fully visible in the views and on the forms, but it’s cheap and you keep the ability to search using lookup, and display the columns in French or English the views if you need to.

Resolution Option 2 – Plugins on Retrieve & Retrieve Multiple

This solution is a little more interesting, but risky. In the Task Activity, we still have one field for the name in both languages and we still concatenate both field values in the primary field.

  • Name English (Single line of text – 100)
  • Name French (Single line of text – 100)
  • Name (Single line of text – 203) – read only for users, populated with “Name English | French Name”

The principle is to write plugins on the Retrieve and Retrieve Multiple events of the Task Activity. In both of these plugins, you need to retrieve the connected user’s language (query the user settings table), and then replace the text being returned in the Name field by the value in the user’s language. This value can be obtained by querying the task activity record and retrieving the name in French or English, or simply splitting the Name field (primary field) with the separator and return the part in the desired user’s language. One plugin will handle the lookup column in list views (Retrieve Multiple), and the other will handle the form views (Retrieve).

Generally, it is not recommended to write plugins on the Retrieve and Retrieve Multiple events for performance reason. If the operations executed in those plugins are simple and optimized, it might be a viable solution. This is a solution that can scale well if you are dealing with more than 2 languages because in all cases, users see only the value in their selected language and the multiple values are transparent to them.

Stay tuned, I have an upcoming post where I provide some metrics about the impact of a plugin on Retrieve and Retrieve Multiple on performance.

Resolution Option 3 – Automated mapping of Option Set with Reference Entity Records

This is a bit of a complex solution, by far the fanciest. The idea is to use an option set instead of a lookup to reference the task activities, but the option set values will be “controlled” with records from the Task Activity CRM entity. It goes like this:

  1. Create a global option set named Task Activity
  2. Create your Task Activity entity with a primary “Name” field. Put the name of task activities in the primary language (language of the CRM org)
  3. When a record is created in the Task Activity entity, use a plugin to create an option set value in the global option set
  4. When a record is updated in the Task Activity entity, use a plugin to update the corresponding option set value in the global option set
  5. When a Task Activity record is deleted/deactivated, use a plugin to update the corresponding global option set value by putting brackets around the name for example, and also pushing the value to the bottom of the option set list
  6. You can then get the CRM Translation file and get the Task Activities values translated as part of the global solution.


4 – Records to Option Set Value mapping

The outcome is that for entities that need to capture the task activity information, there will be an option set field as opposed to the lookup field:


5 – Task Form with Option Set

While this has low impact on performance and leverages the out of the box language-aware option sets, it requires a serious time investment to define the development framework for each entity that required this mechanism to be implemented. It also requires a translator to update the CRM translation on a regular basis (every time there is a deployment). This is a fancy solution that requires a lot of coding and maintenance. In addition to that, you lose the ability to search and filter the content easily like you would do with lookups. You should make sure yours lists are not very long if you don’t want to end up with Option Set lists that are very long which will result in poor user experience.

I have rarely seen companies making such large investments to circumvent the lack of multi-language lookup in CRM. This is usually seen when there are laws that force you to have a system running fully in multiple languages.

Resolution Option 4 – Custom Screen for Lookup views & search

This is another fancy one for which I unfortunately don’t have any screenshot. We want to leverage option sets to “overwrite” lookup values and selection process with the following steps:

  1. Create a set of standardized Web Resources for Lookup Display and lookup value selection
  2. Display the web resources on the CRM Forms and hide the lookup controls
  3. The web resources will have built-in logic to display the value in the language of the current user, as well as a mechanism to allow searches (could be auto-complete based)

Writing a standard web resource control for that purpose is relatively simple. However, you might have additional work to do if you want to take advantage of filtering based on other fields, or custom filters. Also, this solves the issue on the form in the sense that you will see the values in the right language on the form, but for list views, reports etc. the problem will still exist so you’ll need to find another solution there.

Closing Thoughts

As you can see there is no perfect solution. Each organization has to decide the level of investment and risk they want to take to make sure they have multi-language option sets. Living in Canada where we have two official languages, this is a challenge that we often see in public sector implementations because having fully bilingual system is mandated by law. There are very few countries where this is the case (which is probably why Microsoft has not made investments in this area). Most private sector companies will usually impose a primary language for the entire organization.

Hope this helps!

Where to store configuration data in Dynamics 365/CRM?

In almost all the complex systems that I’ve worked with, there has always been a need to store some configuration information. It could be URLs to external APIs or web sites, connection strings to a database for integration purposes, application specific parameters that drive business logic such as Security Roles, Accounts or Contacts. In Dynamics CRM/365, there is often a need to store the same type of information so that plugins, workflow and other integrated applications read them and perform business operation accordingly. In this article, I share the most common options and share some pros and cons associated to each of them.

Key Value Pair Entity

IF you’ve done some application design, you know what the concept of a key value pair table is. In the Dynamics CRM/365 context, it is an entity that contains two required text fields: one for the key and the other for the value. The key represents the name of your configuration variable and the value is, well, the value for the key. For each configuration element that needs to be stored in your system, you create a new row with a key and its value. The images below provide an example of a Key Value Pair entity in CRM in which we stored information to connect to an external web service and the ID of a Security Role, all as text values.

bp-1

1 – List of Key Value Pairs in Dynamics CRM/365

bp-2

2 – Key Value Pair Entity for Example

Pros

  • Very simple data structure
  • Easy to add/remove configuration values
  • Code to read and use the variables does not change over time
  • Retrieving a config element is a fast operation (one row with two columns)

Cons

  • Data type for the value is a text field (not practical for lookups or other data types as you may have to store GUIDs for example)
  • Inability to set default values
  • Inability to use FLS on specific config elements
  • The Keys must be hard-coded in code and/or documented and maintained somewhere

If you are planning to use a Key Value pair type of configuration table, my recommendation is to have one key field as text, and configuration value type field (option set with the type of field – example text, two options) and multiple value columns of different types (e.g. Value (lookup 1), Value (lookup 2), Value (text), Value (two option)). As a bonus, you can add some business rules to prevent the selection of the wrong data type based on the selected configuration value type.

Configuration Entity

Here, the idea is to have an entity in CRM with one field for each configuration element that needs to be stored. In the example below, we have a table that contains information to connect to an ERP web service as well as credentials, and a lookup to a System Admin role (similar information as above). It in this case, there should only one row in the configuration table.

bp-3

3 – System Configuration List View (only one row available)

bp-4

4 – System Configuration Entity form (shows all the configuration fields)

Pros

  • No need to have a list of configuration key names (use the field names enforced at the database level)
  • Each configuration element has the appropriate type (e.g Lookup, text field, two option, option set etc.)
  • Ability to enable Field Level Security on specific parameters
  • Allows for default values for certain data types
  • Easier to setup by an end user (create one row, set values as opposed to create multiple rows with key and value)

Cons

  • Schema change + Code update required anytime a new configuration element is needed
  • You need to ensure there is only one record for the entity (plugin validation on create)
  • Configuration table grows horizontally and not vertically over time

Wrap up

I have used both models extensively and they both work well. For a stable system with not a lot of moving piece, I tend to like the Configuration entity better. For system where things change all the time and new config items need to be added on a regular basis, using the key value pair entity is often more cost-effective. There is also the possibility to use an XML web resource for parameters or the plugin secure and unsecure configuration fields.

Regardless of the method you use, consider caching the configuration data when possible to increase your system’s performance. On the Client side with JavaScript, you can use a few different mechanisms for caching (local storage, cookie). On the server side for plugins, I often use a static cache but this only works for plugins executed in full trust mode (in other words, if you are in CRM Online, no caching on the server side).

Cheers!

 

CRM Plugin Code Structure – By functionality or by event?

When we work on CRM plugins, there is a key decision at the beginning of the development cycle when it comes to structuring your plugin code. There are two main ways of writing your plugins :  by events or by functionality. In this post, I will describe the two approaches and discuss some of their pros and cons.

Plugins can be described as handlers for events fired by Microsoft Dynamics CRM (source). There can be multiple handlers for single events.  Let’s use an example for the purpose of this post.

For the event, we’ll use the creation of a case (pre operation). We will consider that when  the case is created, there are two actions that need to be performed : generate and assign a unique case number and validate that required fields have authorized values in them.

Plugin structured based on Events

For the plugin structure based on event, it means we’ll have a single plugin registered on the Case Pre create event, and inside the plugin class we’ll have two business logic blocks of code to execute (one to generate the unique number, the validate the required fields).

SNAGHTML4e81484     SNAGHTML4e74f7f

Plugin structured based on Functionality

In this case, we’ll have two plugin classes registered on the same event (again, one plugin for unique number generation and another to validate the required fields) – Sorry, no screen shot here but you get the idea Smile.

Pros and Cons

Functionality Based Plugins

  • Pros
    • Ease to see what plugins does what when looking at Plugin Registration tool (or similar tools) because of more descriptive feature name in plugin name
    • Ability to disable specific features for various scenario (e.g. disable system integration or auto calculation plugins during data migration)
    • Unit Tests can be written against a plugin class to test one functionality
    • Provides the ability to easily write generic plugins and register on multiple events by any power user
  • Cons
    • Large amount of plugin classes
    • Large amount of registered plugin steps; can become big and hard to read/maintain

Event Based Plugins

  • Pros
    • Plugin registration is straight forward and easy to maintain
    • Ease to easily the operations performed at each event when looking at the code
    • Plugin classes are standardized : always tied to an event and single point of entry for all developer to see actions executed on the event
    • Unit tests can be written against specific Business logic methods and/or classes (even independently from the plugin execution context depending on how they are written)
  • Cons
    • Must use alternate mechanism to disable specific features if needed (e.g. configuration data element)
    • Possible timeout if executing multiple large business logic blocs (mind you, if you have a timeout in a plugin – which happens after two minutes, you probably have a design issue)
    • General  dependency to having a developer around
      • Generic business logic code blocks can be written but a developer is required to insert the business logic on additional events
      • To view the all operations performed for an event, a developer needs to look at the code

So which model should you use?

I have used both models heavily on various occasions. For me personally, the decision on which one to use comes down to a project’s needs and a coding style preference. As an example, if you know you’ll have a lot of generic features and want to have reusable plugins, you are better off using the functionality based model. The same applies if you know there are processes that require to disable specific functionality on a regular basic. On the other hand, if you project is relatively small and includes simple business logic on a few events, the event based approach can be a good choice. Feel free to add feedback in the comment section if you see other pros and cons for each of these models or want to share experience in the area.

Exchanging data between CRM Forms and IFRAMEs

One of the most common requirements when we add content in IFRAMEs or Web Resourses in CRM is to have the ability to communicate with the calling or source CRM form to perform all sorts of operation. This article explains how this can be achieved using the postMessage JavaScript messaging mechanism.

What does postMessage do?

It’s a JavaScript method which was initially created to facilitate cross-origin communication between web pages. There are often valid scenario in which we need to display a page from another website in a new window or in an IFRAME. That’s the easy part. The more complicated part is when there is a requirement to perform some operations on the source page based on a action that occurs on the external page in the new window or IFRAME.

In the example below, consider we have a contact form that displays an external page in an IFRAME. When a button in clicked in the IFRAME, information (example, a lookup value) is passed to the CRM form, the value is set on the screen and the form is saved.

Step 1 – Write methods for the CRM Form: Register Listener, Message Handler  

The code below contains two methods, the first one (RegisterListener) sets a method that will be called if the postMessage is invoked (UpdateContactLookup). 


SADAX.Contact =
{
   RegisterListener: function () {

     if (window.addEventListener) {
       window.addEventListener('message', SADAX.Contact.UpdateContactLookup, false);
     }
     else { // IE8 or earlier
       window.attachEvent('onmessage', SADAX.Contact.UpdateContactLookup);
     }
   },

   UpdateContactLookup: function (event) {

     var origin = "";
     if (event.domain) origin = event.domain; // IE
     else if (event.origin) origin = event.origin; // FireFox - Chrome

     if ("https://source" == origin) {

       if (event.data != null) {

         var entity = SadaxJSON.parse(event.data);
         if (entity) {

           var value = new Array();
           value[0] = new Object();
           value[0].id = entity.Id;
           value[0].entityType = entity.LogicalName;

           var lookup = Xrm.Page.getAttribute("sadax_referencecontactid");
           lookup.setValue(value);
Xrm.Page.data.save();
}
}
else
{
alert("This message has been posted by an unknown source ('" + origin + "', expected 'https://source').");
return;
}
} 
}

Step 2 – Register the listener on Form’s OnLoad event

image

Step 3 – Write Code for the IFRAME to post the Message from the IFRAME

After the business logic execution, the postMessage method is called on the parent CRM form as follows:

function SetContactLookup(entityReference)
{
   var entity = {};
   entity.Id = entityReference.id;
   entity.LogicalName = entityReference.entityType;

   window.parent.postMessage(SadaxJSON.stringify(entity), "https://source");
}

Comments / Wrap up

At step 3, using the postMessage on the window.parent will cause the SADAX.Contact.UpdateContactLookup method to be fired on the parent CRM form. Notice that the method receives an event object as a parameter. The content of the object slightly differs based on the browser being used (IE vs rest of the world). Mostly, you should pay attention to the event.domain or event.origin attributes. This is used to validate the website that posted the message is safe (i.e. the one you are expecting).

There is also an event.data attribute that contains parameters that are sent from one page to another. In this case, we are using a renamed JSON library to stringify our custom object types. Passing an object without stringifying it would work, but we found it didn’t work well in all browsers/version. The reason for the renamed JSON library is again browser compatibility reasons. If IE8 is out of scope for you, you probably do not need this.

Notes:

  • This also work for web resources opened in a different window using window.open or Xrm.Utility.openWebResource
  • IE8 doesn’t allow to postMessage to other windows, only to iframes.
  • I haven’t tried this in CRM Online so you can try it by yourself if need be.

Dynamics CRM Archiving Solutions Revisited

I wrote about Archiving solutions for Microsoft Dynamics CRM about 2 years ago. I still get a lot of questions from the article and from customers in the field about what they should do when it comes to archiving their Dynamics CRM data. While there is no obvious answer, my generic approach is to make sure my clients understand that they shouldn’t try to build an archiving solution before their system has become slower. They should see it more as an opportunity to perform a thorough review of their implementation and isolate the bottleneck(s) and pain point(s) and see if those can be fixed.

A few months ago, I gave a presentation on the topic that you can see below. I go from the reasons to archive data to recommendations. Hope this helps!

Dynamics CRM Solution Architecture

Hello readers!

I just completed a series of very animated presentations on Solution Architecture for Dynamics CRM in a few different cities in the east of Canada. I thought I would share the slide deck.

As a summary, I complied a few thoughts about the CRM Solution Architect’s role and typical design consideration. Enjoy the content and feel free to reach out to me with questions and comments.