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.

October 12, 2012

TypeScript CRM 2011 client scripting definition file

CodePlex project page

TypeScript?
Last week Microsoft went public with a JavaScript super-set language called TypeScript. The idea behind this language was to keep it compatible with JavaScript (all JavaScript code is TypeScript code) and add a few features which make it easier to manage large code bases.
This features include compile time type checking and well known OOP structures like classes, interfaces and modules. OOP structures were possible to emulate in JavaScript but required the developer to write code that wasn't very easy to read and understand.

Off course TypeScript code is not understood by browsers. The code you write in TypeScript is compiled to pure JavaScript using the type script compiler (tsc). You then reference that JavaScript in you're web pages. The compiler tries to keep the structure of the generated JavaScript code as close to the original TypeScript code as possible, so it's easy to debug.

In one sentence TypeScript makes JavaScript easier to write, maintain and safer.

The TypeScript team also created a plugin for Visual Studio 2012 that provides syntax highlighting, automatic background compiling and more importantly IntelliSense for TypeScript code. In order to use that feature for existing JavaScript code it is required to create a definition file (something like header files in C/C++). Because I'm mainly a Dynamics CRM developer I thought it would be worthwhile to create such a definition file for Dynamics CRM 2011 client scripting - the Xrm.Page JavaScript library.

Simple manual (if you already have TypeScript installed):
1. Download the Xrm2011.d.ts file from the link above.
2. Add it to your project.
3. In your TypeScript code reference the definition file by adding
/// <reference path="Xrm2011.d.ts" />
on top of the file.

Advanced manual (if you don't have TypeScript installed):
1. Download & install the TypeScript plugin from here.
2. Optionally download  & install the Web Essentials 2012 extension for Visual Studio 2012 for improved code handling.
3. Proceed with the Simple Manual

Why should I use TypeScript instead plain JavaScript?
The simple answer is that it makes coding much easier and less error prone. Please look at the following examples:
Design time type information


IntelliSense code completion

Design time check


Comments?
If you see any errors or possibilities to improve the definition file, please write a comment.

October 8, 2012

Dynamic CRM + IE 10. Scrollbar position indicator barely visible

When I started working on Windows 8 right after the RTM release for partners I noticed an annoying issue. The scrollbar position indicators are barely visible. Maybe my monitor isn’t a professional Eizo, but I didn’t have this issues in previous versions of IE.

Look at this screenshot:
image
The color difference between the background of the scrollbar and the position indicator is very small. You have to really concentrate to see where it is.

Look at the close up:

image                          image

On the left the original, on the right with marked position of indicator. Doesn’t look very clear, does it?

The colors are:

Background:#E3E8ED
Indicator: #E9EDF1

If someone knows a good solution, please post it in the comments. It’s a minor issue, but quite annoying.