September 22, 2015

Top 8 errors made by Dynamics CRM developers - Part 1 - Not facilitating the pre-event plugins


Having spend some time working as a CRM focused developer I often see the same development issues reappearing again and again. The root of the problem is that CRM programming is kind of special and previous experience from working with SQL databases or Web Development, although very precious and desired, can cause certain aspects of the code to be developed not exactly how it should have been.
In this series of posts I’ll try to summarize the most common mistakes or misconceptions I often see. As a matter of fact, because of my previous SQL and Web experience, I made some of them myself when starting my work with CRM several years ago.
To keep this a blog I have decided to split it up in a series of posts. The subjects I intend to cover are:
  1. Not facilitating the pre-event plugins (this post)
  2. Choosing the right query method: FetchXML vs QueryExpression vs LINQ
  3. Querying for all columns
  4. No or invalid plugin filters
  5. Unsupported DOM manipulation
  6. Getting the true value of an attribute inside a plugin
  7. Not understanding how solutions work
  8. Putting business logic client side 

Issue #1 – Not facilitating the pre-event plugins


This is probably the most common issue I see, and also the one causing the most problems when it comes to performance.

Simple rule is:
If you want to update the record that triggered the plugin, update the values directly in the target entity, using a pre-operation plugin. Do not use the .Update() method of the CRM web service.

A good example would be filling in a “full name” based on the first and last names. There are off course several ways of doing this, but let’s assume we use a plugin (which is probably also the best choice – see Issue #8).

Let’s see a short reminder on how the Dynamic CRM plugin execution pipeline looks like:
image
Fig 1 – Dynamics CRM plugin execution pipeline

As we can see it start with an event, like a certain field being updated or a record being created.
Next we have the place to register pre-validation plugins. Pre-validation means that even if we, for example, decide to limit an integer field to the 0-100 range and a user types in 1000, this plugin will still get executed. We can correct the value in code, without the user seeing an error message.
Right after the pre-validation plugins the “platform” performs the validation, like throwing errors when values are not in expected range.

Now the pre-operation plugins get executed, and this is where it gets interesting. We are still before the core database operation, so nothing has been stored yet. On the other hand we have access to the data that will be passed over to SQL and can freely modify it. This is the place where all changes to the current record should be done. Whatever we change here will modify the state of the object passed to SQL.

In the above example we fill in the full name. See how the value we filled in is then later passed to SQL and stored in the DB. This is the correct way of doing it. No further plugins will be triggered.

The anti-pattern looks like this:
image
Fig 2 – Update anti-pattern

What happens here is that we execute and completely unnecessary update, causing the whole pipeline to execute two times instead of once. In the worse case scenario we have setup our plugins to trigger on change of all attributes and then check the execution depth to avoid infinite loops… That is a no no no…

Some code examples


Let’s say we want to have a plugin that changes the last name of a contact to upper case. This should be performed on each update of the last name.

This is how it should not be done:
// Post-update plugin
// Registered on update of LastName
public class LastNameToUpperPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Get context
        IPluginExecutionContext context = (IPluginExecutionContext)
            serviceProvider.GetService(typeof(IPluginExecutionContext));

        // AVOID INFINITE LOOP
        if(context.Depth > 1)
        {
            return;
        }
           
        // Get target contact
        Entity entity = (Entity)context.InputParameters["Target"];
        Contact targetContact = entity.ToEntity<Contact>();

        // Get organization service
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)
            serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService orgService = serviceFactory.CreateOrganizationService(context.UserId);

        // Business logic
        string lastNameUpper = (targetContact.LastName ?? "").ToUpper(CultureInfo.InvariantCulture);

        Contact updateContact = new Contact()
        {
            ContactId = targetContact.Id,
            LastName = lastNameUpper
        };

        // !! Here we call the .Update()
        // This will cause an INFINITE LOOP
        orgService.Update(updateContact);
    }
}
In general, whenever you see checking the execution depth, with 99,99% probability there is something wrong with the code.

What would be a much better solution is:
// Pre-update plugin
// Registered on update of LastName
public class LastNameToUpperPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Get context
        IPluginExecutionContext context = (IPluginExecutionContext)
            serviceProvider.GetService(typeof(IPluginExecutionContext));


        // Get target contact
        Entity entity = (Entity)context.InputParameters["Target"];
        Contact targetContact = entity.ToEntity<Contact>();

        // Get organization service
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)
            serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService orgService = serviceFactory.CreateOrganizationService(context.UserId);

        // Business logic
        string lastNameUpper = (targetContact.LastName ?? "").ToUpper(CultureInfo.InvariantCulture);

        targetContact.LastName = lastNameUpper;           
    }
}

How to spot this?


Whenever you see the execution context depth checked there is probably something wrong...

November 7, 2014

Custom workflow activity not visible in plugin registration tool

When trying to register a plugin assembly containing custom workflow activities to CRM Online using the Plugin Registration Tool from the 2013 SDK, the custom workflow activities were not visible. Only plugins.

Tried changing the assembly major version, and the key which signs the assembly - no luck.

The solution was to use the Plugin Registration Tool from the pre-release 2015 SDK found here - http://www.microsoft.com/en-us/download/details.aspx?id=44567.


September 25, 2014

Wrong SaveMode on Activation

Latest CRM 2013 on premise. execObj.getEventArgs().getSaveMode() when clicking Activate should be 6, but is 1 - the same as on Save.

http://msdn.microsoft.com/en-us/library/gg509060.aspx#BKMK_GetSaveMode

August 28, 2014

CRM plugins. The proper way of updating values of records in context.

In this post I will try to describe how to properly, inside a plugin, change attribute values of the record that triggered the create or update operation. From time to time I stumble upon code that threats the context record (the one on which a create or update operation triggered a plugin) as any other record, which is wrong.

How it should not be done:

  1. A plugin step is registered on the create event of entity E.
  2. Record A of entity E is created.
  3. The registered create plugin step fires.
  4. (…) Some business logic (…)
  5. Record A is updated by calling the organization service .Update() method.

Or even worse:

  1. A plugin step is registered on the update vent of entity E.
  2. Record A of entity E is updated.
  3. The registered update plugin step fires.
  4. (…) Some business logic (…)
  5. Record A is updated by calling the organization service .Update() method.
  6. The registered update plugin step fires again (since an update was done).
  7. Inside the plugin the .Depth property of the execution context is checked to avoid infinite loops.

What is wrong in both these scenarios is that an Update request is used to update the context record. This causes:

  1. Unnecessary load on the CRM application and database.
  2. Infinite loops in plugins.
  3. Possible transactional  errors and performance issues, which could lead to plugins failing.

The above approach might be used by analogy with SQL databases. But the CRM service is not a SQL database, and requires a different approach.

The proper way of doing this is registering the plugin step (create or update) in the pre event inside transaction phase (20) and modifying the attributes directly in the target entity. All changes done to entity attributes in the “20” phase will be stored, without any unnecessary round trips and service calls.

image

This is a simple example showing a plugin that sets new_attribute3 to a string concatenation of new_attribute1 and new_attribute2. It is of course simplified, does not check validate the values, check for nulls, etc. but it proves the point.

If this code is registered to execute on the pre operation (20) phase, the value of new_attribute3 will be updated, without any other operations. This is because when in phase 20 it modifies the record before CRM does the core database operation (30). So anything we change here, will be what gets later pushed to SQL.

March 16, 2014

Dynamics CRM - Delete does not trigger Disassociate; Need pre validation plugin to retrieve existing N-N relationships.

Whoever worked with multi-multi (N-N) standard relationships in CRM knows that you can trigger plugins on the Associate and Disassociate messages. They fire when you add / remove a N-N relationship between two records.

You would expect that when you delete one of the records from the N-N relationship this would also trigger a Disassociate message, after all the association is also removed. It does not.
Because of that if you want to program something that triggers whenever a N-N relationship between two records is removed is is not enough to trigger on the Disassociate message. You also need to trigger your logic on the Delete (and probably SetStateDynamicEntity, for inactivation) messages.

So far so good, but how to retrieve all the N-N related records from the other entity? This can be done by querying the "hidden" N-N cross entity, which can be found under "Relationship Entity Name" when you open the properties of any N-N relationship.

Using LINQ the query would look something like this:

// data - instance of the service context
from nn in data.nn_relationship_entity
where nn.relationship1id = FILTER_ID
select nn.relationship2.Value

An important thing to note is that if you run this in the Pre-Operation stage of the Delete message it will return 0 rows! The correct place (one of the very few examples) is the Pre-Validation phase. If run there it will correctly return the ID's of all related records, on which you can then run you disassociation logic.

Hope this helps someone...

November 6, 2013

Simulating a custom web service in Microsoft Dynamics CRM Online

 

The problem

Stating the obvious - it’s becoming more and more popular nowadays to move functionality from the server to the client side. Especially in web applications where rich client applications with asynchronous data retrieval and processing allow a much richer user experience.

This trend is also present in Dynamics CRM with the introduction of Web Resources, which in theory allow you to build any kind of functionality and embed it into CRM – as IFrames launched from the main menu, popups opened from ribbon buttons, parts of dashboards etc. The possibilities are unlimited.

Dynamics CRM exposes web services and methods which allow to launch basically any functionality exposed by the SDK from the client side (using different methods like REST or direct organization service requests). Although it gives a lot of possibilities it’s basically limited to atomic operations on a single record and fetch requests with a very limited query language (FetchXML or even more so OData).

In cases where the business logic is more complicated and requires fetching data from several places this approach will be extremely inefficient  and time consuming to develop (think live updating segmentation results on the client side for example). Another example where using the build in web services is not the best idea is when you need to display data aggregated from maybe thousands (millions) of records which cannot be achieved by single FetchXML queries. Downloading all that data to the client just to process it and display some result will be slow, error prone and time consuming to build.

In a broader view the “client” doesn’t necessarily have to be a web browser. It can as well be a windows application, external service etc.

Summing up, this is what we would like to avoid:

image

On-premise solution

In an on-premise environment the natural solution would be to create a custom web service (like WCF, ASP.NET MVC Web API etc.) and host it in IIS next to CRM. In that service we can write basically any code using the full server side SDK. What we get is something like this, which probably is the best solution:

image

What about online?

Unfortunately this cannot be done in CRM Online. Simply because we cannot deploy any services next to CRM. We could try on Azure in the same datacenter but that’s an additional cost and component to maintain. Also this will always be slower than hosting it directly on the same machine, network latency can be a serious issue when doing thousands of requests.

Are we stuck with doing multiple requests to get our data? No.

There are at least two possible solutions to the problem.

Solution 1 - Request handling entity

The first solution would be to create a dedicated entity for request handling. It could be generic with two text fields – request and response into which we put the request parameters and calculated response or domain specific with exact fields matching the request we are making.

We than create a record of that entity after which a pre-operation plugin fires, does all the calculations and writes them back to the response field(s). Afterwards we query the entity to retrieve the response and delete it. Graphically it would look like:

image

This method requires 3 web requests. Alternatively we could skip the 3rd one (cleanup) and do that with a workflow or just leave the request records and clean them up on schedule.

A big advantage of this method is that since we process all the data in a plugin we gain transactional consistency. If anything fails during the processing all the changes are rolled back.

This method can be used to do all types of operations in CRM – not only data retrieval, but also creating and updating existing data.

The downside is that we actually create a record in CRM that doesn’t have any business meaning. It does waste a little recourses and might be fragile to transactional locking.

Solution 2 – Use exceptions to your advantage (only good for querying data)

There is another solution that doesn’t require for any records to be created in CRM. When an InvalidPluginExecutionException is thrown inside a CRM plugin, we can provide it with a error message that is returned to the client. Why not use that error message to actually return the response? Smile

image

This way the “request helper entity” record is never created and we get the response directly. No need to re-query to retrieve the response and no need to manage the unnecessary helper records.

The only downside is we cannot do any processing of data in this approach, only query it. This is because when the exception is thrown we rollback all the changes we did in the system.

Example of how to read the response from Solution 2

The error text returned by CRM will always be in the form:

SOME_GENERIC_TEXT OUR_ERROR_MESSAGE SOME_GENERIC_TEXT

The simplest approach would be to clearly separate our response from the rest of the message using an unique separator like @##@ on both sides of the message. This way we get

SOME_GENERIC_TEXT @##@RESPONSE@##@ SOME_GENERIC_TEXT

Which is simple enough to parse in any client technology using string split.

When using a HTML client application this would look something like this

$.ajax({
    type: "POST",
    contentType: "application/json; charset=utf-8",
    datatype: "json",
    url: Xrm.Page.context.getServerUrl() + "/XRMServices/2011/OrganizationData.svc/MyEntitySet",
    data: jsonRequestData,
    beforeSend: function (XMLHttpRequest) {
        XMLHttpRequest.setRequestHeader("Accept", "application/json");
    },
    success: function (data, textStatus, XmlHttpRequest) {
        // Should never get here
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {       
        var responseText = XMLHttpRequest.responseText.split("@##@")[1];
    }
});

Summary

This article presented two methods of client side retrieving and processing data in CRM online which are a good alternative to building dedicated web services.

May 6, 2013

CRM 2011 ribbon button data dependency

 

The problem

It is not uncommon for a button in the ribbon to be enabled / disabled based on data from another (probably related) entity, or fields from the current entity which are not on the form.

In such cases it is necessary to query the organization service in order to retrieve the required data.

The most commonly used AJAX requests by default are asynchronous. This means that a callback function is called with the response as argument.
$.ajax({
  dataType: "json",
  url: url,
  data: data,
  success: success
});
image

This method is great in general, because it doesn’t block the UI thread in the browser. Although when used in functions determining if a ribbon button should be enable they won’t work. The obvious reason is that the callback is called after the base function has finished. So the base function that is supposed to return the yes/no answer does not have access to the results.
image

 

The solution

image

This synchronous behavior is trivial to achieve.

var jsonResponse= $.parseJSON($.ajax({
            type: "GET",
            dataType: "json",
           
url: Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc/ContactSet?QUERY
   
        cache: false,
            async: false
        }).responseText);

Setting the async parameter to false will cause the query to be synchronous. It will block the UI thread, but in most cases for such a short period of time it’s barely noticeable.

After retrieving the jsonResponse all you need to do is to parse it and return true / false from the base function.