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.

August 10, 2012

Mapping SkyDrive, DropBox etc. folder to drive

This post is not related to MS CRM in any way, but it might come handy so I thought it’s worth sharing.

When installing cloud based storage like SkyDrive or DropBox you get a nice link in the Favorites section of Windows Explorer. Something like this:
image

This works very nice until the application shows you the “modern” save or open file dialog.

But what happens if an application is “legacy” or for some different reasons (I’m guessing Java) is using the older versions of the dialogs. You get something like this (example is from Adobe Reader X):
image

Navigating to your cloud based storage gets a little annoying. You have to click [Computer], [C],  [Users], [USER_NAME], [SkyDrive]. That’s 5 clicks just to get to the stupid folder. Someone could say that you only need to type in "%UserProfile%\SkyDrive, but lets be honest – that’s not something most of us think of in such situations (also moving the hand away from the mouse in order to type is quite annoying Smile ).

Wouldn’t it be nice to be able to map such folders to a drive letter? That way it’s only 2 clicks away.

The solution is quite easy – a windows command called subst. The syntax is as follows:
C:\Users\kowgli>subst /?
Associates a path with a drive letter.

SUBST [drive1: [drive2:]path]
SUBST drive1: /D

  drive1:        Specifies a virtual drive to which you want to assign a path.
  [drive2:]path  Specifies a physical drive and path you want to assign to
                 a virtual drive.
  /D             Deletes a substituted (virtual) drive.

Type SUBST with no parameters to display a list of current virtual drives.

So in my case just typing in subst Z: C:\Users\kowgli\SkyDrive almost solves the problem. The problem is this is not persistent across system reboots. In order to overcome this one of the simple solutions is to ensure the command gets executed each time the system start – read HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

image

Adding the command to that registry area solves the problem. And now our folder is permanently mapped to a drive, which saves us 3 clicks a couple of times per day Open-mouthed smile

I know for some people this problem is trivial, but still … I thought it would be nice to share.

Cheers

August 9, 2012

CRM 2011 plugin registration error “Inheritance security rules violated by type”.

When trying to register a plugin using an external dll ILMerged into it I came across the following error:

Unhandled Exception: System.TypeLoadException: Inheritance security rules violated by type: 'XXX.YYY.ZZZ.Plugins.ABC'. Derived types must either match the security accessibility of the base type or be less accessible.
at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes)
at System.Reflection.RuntimeAssembly.GetExportedTypes()

I remembered I had this issue before. The reason is that some legacy external libraries don’t follow .NET 4.0 security rules. The solution it actually quite simple – revert back to .NET 2.0 security. Simply add the following attribute anywhere inside you’re code (after the using statements):

[assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)]