January 5, 2017

MVP again for 2017, transition to the new Dynamics era

January 1st I received my third Microsoft MVP Award for my contributions to the Dynamics community, the category is still "Business Solutions" as Microsoft did not make new changes to the MVP Award structure.
It's an honor for me to be part of this group, to "celebrate" the event I will use this post to write some of my thoughts about the MVP/Dynamics world.

Currently there are a bit less than 100 MVP awarded for the Dynamics CRM competency (I don't have the exact number) but between my Twitter feed and the Dynamics Community forums I can easily write a list of another 100 great people that works with Dynamics CRM and are not MVP. They write blog posts, create useful tools, tweet relevant news and their contributions are valuable to everybody in the community. The fact that they don't have an award doesn't make their job, their opinions, their experiences less important, in the same way my contributions have not an higher value because I am an MVP, I can consider the award a small proof of my competences, but it doesn't define totally me or what I do.
The community is central, without users sharing questions/answers/thoughts, no matter if the topics are basic or advanced, the MVP program will not have reason to exist.

During the last year I had the chance to participate also to some "offline" events: April in Rome I joined the Western Europe MVP & Community Day 2016, October in Milan I joined the Microsoft Future Decoded and November in Seattle the annual MVP Summit.
All these three events were amazing, I had finally the opportunity to meet in person fantastic people and I hope to meet them soon again. If you want to get an idea you can read Leon Tribe post about the summit https://thatcrmblog.wordpress.com/2016/11/19/post-summit-debrief/

Regarding my contributions in 2016, I think the most important is the Dependent OptionSet Generator, it's a small tool but I know people using it and they find it useful, when you create a tool the goal is to simplify a process, not everybody sends spaceships to Mars (I am looking at you Elon Musk), and the saved time can be used for something else or spent outside work.
Another contribution that I am proud is that I got back the Microsoft Community Contributor (MCC) badge, it's assigned every 6 months, and in the last year my number of answers were not enough to get it.
What I failed regarding my contributions in the last year? Definitely blogging, I wrote only few posts, maybe 2017 will inspire me to write more.

2016 is also the year the Dynamics ecosystem changed and it's now toward a new direction. The "Dynamics 365" momentum now can look like just a rebranding, but it's definitely more, inside and outside of what was formerly known as Dynamics CRM. The platform is HUGE with all the available solutions like Field Service, Project Service and the Portals, it's TERRIFIC considering the integrations with PowerBI, Azure and AX, it's a GREAT future for the Dynamics platform and for the people works with it (the MVP summit was held during the US elections, so now I unintentionally use some words).

If you arrived at this point of my unexpected long post, I wish you Happy New Year and I hope you will reach your goals for 2017!

September 5, 2016

Dependent OptionSet Generator - Overview - Part 1

Some days ago I released a new Dynamics CRM tool called Dependent OptionSet Generator.
As the name suggests it helps to create and update dependent OptionSets, one of the possible approaches to filter data inside CRM UI.

Scott Durow wrote an overview about this argument on his blog: "Option-Set, Lookup or Autocomplete", it's very useful if you plan to use dependent OptionSets in order to know the pro and cons of this approach.

I want to thank Scott not only for his post but because he found the time to meet me when I was in London a couple of months ago (photo). He was the first person I talked about this little project and we had a pleasant discussion not only about Dynamics CRM, thanks again Scott!
During my short visit in London I also met again Ramón Tébar Bueno and it's really nice to spend some time with other members of the Dynamics CRM Community, plus he took me to a typical British Pub!

Now back to the main reason of this post, the Dependent OptionSet Generator.
Starting from CRM 2011 the possibility to filter OptionSets entries was available thanks to the Xrm supported methods. Microsoft also provided a solution inside their CRM SDK to implement the dependent OptionSets but the most tedious process, the generation of the XML file required to map the entries, was delegated completely to the user.

Creating manually the XML document has always been a bummer, especially when you need to deal with several entries, so developers and consultants suggest to use filtered Lookups instead.
However there are implementations where OptionSets are preferred due to the Multi-Language support, to facilitate CRM users (at eCraft, the company I work for, we often have customers with Finnish and Swedish users) or because it's required by the law (for example in some provinces of Canada).

Microsoft kept updated its Dependent OptionSet solution during the years and with the latest CRM 2016 version they changed the configuration format structure from XML to JSON, probably in order to simplify the creation of the file.

My solution consists of two parts:
  • The first part is the JavaScript Library to be included inside the CRM forms in order to filter the OptionSets
  • The second part is a Web Application to build and maintain the JSON configuration required by the JavaScript Library
This post will cover the first part, I will write another post (or more) regarding the Web Application.

The JavaScript Library included in my solution is based on the CRM 2016 SDK version called sample_SDK.DependentOptionSetSample.js, you can find the source code here. Except for the first point (Different Namespace) all the other changes were done in order to make the script compatible with CRM 2011 supported browsers.

  • Different Namespace: because I didn't change the name of the functions I preferred to use a different namespace (DO instead of SDK) in order to avoid issues if the SDK library and my library are loaded in the same form.

  • JSON: The CRM 2016 library uses JSON, but the original Microsoft Library created for CRM 2011 uses XML. When the CRM 2011 library was created Dynamics CRM supported only Internet Explorer, including old versions like IE7. These old IE versions don't have the JSON object, so (probably) they decided to parse an XML object instead. My library in order to be compatible with these IE versions includes the JSON2 library. I can include it without issues because the first line of the library checks if JSON is already defined
    if("object"!==typeof JSON)JSON={};
    
    in this way old browsers can support JSON methods like JSON.parse.

  • getClientUrl: This Xrm method was introduced with CRM 2011 UR12, but my library in order to be compatible with pre-UR12 CRM 2011 instances checks if getClientUrl is available before using it. I used this code snippet in many of my samples in order to avoid creating a JavaScript only to handle CRM 2011 versions:
    var serverUrl;
    if (Xrm.Page.context.getClientUrl !== undefined) {
        serverUrl = Xrm.Page.context.getClientUrl();
    } else {
        serverUrl = Xrm.Page.context.getServerUrl();
        if (serverUrl.match(/\/$/)) { serverUrl = serverUrl.substring(0, serverUrl.length - 1); }
    }
    
  • response and responseText: Older versions of Internet Explorer don't implement the response property inside the object returned by the XmlHttpRequest, so if the property is not defined we will use the responseText instead.
    if (this.response !== undefined) { wrContent = this.response; }
    // handling responseText for older IE versions
    else { if (this.responseText !== undefined) { wrContent = this.responseText; } }
    
  • setTimeout: The setTimeout syntax used inside the SDK sample is not compatible with older IE versions, an easy fix is to wrap the function called inside an anonymous function:
    // original SDK sample code
    setTimeout(SDK.DependentOptionSet.filterOptions, 100, parentFieldParam, childFieldParam, dependentOptionSet);    
    // setTimeout rewritten for older IE versions
    setTimeout(function() { DO.DependentOptionSet.filterOptions(parentFieldParam, childFieldParam, dependentOptionSet); }, 100);
    
  • getClient and CRM for Tables and Phones: The SDK sample handles also the compatibility with CRM for mobile devices, but in order to handle the call to the method Xrm.Page.context.client.getClient() it's necessary to check if the context object contains the client property and its getClient method:
    if (Xrm.Page.context.client !== undefined && Xrm.Page.context.client.getClient !== undefined) {
        // ... rest of the code
    }
    
  • forEach: The SDK sample uses forEach to iterate the available values for the child OptionSet, but forEach is not available for older IE versions, the code has been rewritten to use a standard for cycle:
    //original SDK sample code
    validOptionValues.forEach(function (optionValue) { /* ... */ })
    // standard for cycle
    for (var count = 0; count < validOptionValues.length; count++) { /* ... */ }
    
Making the library compatible with CRM 2011 was more an exercise for me, CRM 2011 is officially not supported and I hope that many instances have been already migrated to newer versions, but I am aware that this is not always possible.

However the main part of my solution is the Web Application to create/update the JSON configuration, if you are already using the CRM 2016 SDK Sample in your CRM, you can use the Web Application without using my library and just update the Web Resources.

September 3, 2016

Passing Arrays to JavaScript Web Resources as parameter

Despite the availability of Business Rules, JavaScript is still an important way to customize Dynamics CRM UI, especially in complex scenarios (or when you just need to hide a section).

If you ever need to pass an Array as parameter inside the Event Handler form, you can declare it with the square brackets or using the Array keyword:
// square brackets
[1, 2, 3, 4 ,5]
// Array keyword
new Array(1, 2, 3, 4, 5)
CRM Event Handler:


As example we write a function to hide fields passing their logicalname as an array:
["name", "accountnumber", "telephone1"]
the function handles the parameter in this way:
function HideFields(fields) {
    for (var count = 0; count < fields.length; count++) {
        if (Xrm.Page.getControl(fields[count]) != null) {
            Xrm.Page.getControl(fields[count]).setVisible(false);
        }
    }
}
If a parameter is an Array, multiple parameters can still be passed inside the Event Handler. For example:
// note the comma before the array is declared
true, ["name", "accountnumber", "telephone1"]
In this way we are sending a boolean as first parameter to our updated function:
function ShowHideFields(isVisible, fields) {
    for (var count = 0; count < fields.length; count++) {
        if (Xrm.Page.getControl(fields[count]) != null) {
            Xrm.Page.getControl(fields[count]).setVisible(isVisible);
        }
    }
}
There is another way to pass multiple parameters without declaring each parameter inside the function definition and without using an Array: the arguments variable.
In JavaScript the arguments variable holds automatically all the parameters passed to a function.
We can rewrite the previous example, inside the Event Handler we pass the values as separate parameters, not as an array:
// no square brackets, no Array Keywords, just 3 separate parameters
"name", "accountnumber", "telephone1"
and our function is simply this one:
function HideFields() {
    for (var count = 0; count < arguments.length; count++) {
        if (Xrm.Page.getControl(arguments[count]) != null) {
            Xrm.Page.getControl(arguments[count]).setVisible(false);
        }
    }
}
But if we want to handle a specific element (like the first element) we need to take care inside the code:
// we decided that the first parameter will contain the value for the isVisible variable
true, "name", "accountnumber", "telephone1"
function ShowHideFields() {
    // this function requires at least 2 parameters
    if (arguments.length > 1) {
        var isVisible = arguments[0];
        // we start the for cycle from 1 instead of 0
        for (var count = 1; count < arguments.length; count++) {
            if (Xrm.Page.getControl(arguments[count]) != null) {
                Xrm.Page.getControl(arguments[count]).setVisible(isVisible);
            }
        }
    }
}

August 16, 2016

Fix the "Role Error" message when updating security roles

TL;DR: This solution has been posted on Dynamics Community Forums by Nithink.K quoting a Microsoft support answer (link). This post provides an easy solution to fix the issue.

If you have a CRM Online instance and recently you tried to update a security role probably you got the following error:



Role Error - Users cannot add privileges to or change access levels for roles to which they are assigned. For help with changing a role, contact your Microsoft Dynamics CRM administrator.

The error is misleading, because in my case the user had only the "System Administrator" role and I was trying to update the "Sales Manager" role, also the log file didn't provide additional information, it just contained the message "Invalid privilege depth".

A solution has been posted on Dynamics Community Forums (you can find the whole thread here) and it's about a wrong privilege that has been assigned to the "Data Performance Dashboard" entity under the core records. This OOB entity is "Organization" type (meaning the privilege can be only "Organization" or "None") but in the CRM Online instances affected with this problem, the privilege is set to "User":



The solution is to set the privileges to "None", after this change the security role can be edited or copied again. I started a new CRM online trial and the correct configuration is "None" for all the security roles except System Administrator (that can't be customized) and System Customizer that has these privileges set to "Organization".

Because it's a tedious process to edit all the security roles one by one, you can use the "Role Updater" tool included inside the XrmToolBox, with this tool you can bulk update the security roles removing or adding privileges in few clicks.

After you started the tool, click on "Load Roles and Privileges" button and select all the users except "System Administrator" and "System Customizer"



After you click "Next", search for "data" and select the privileges related to "Data Performance Dashboard" entity and click the "None" button



When you are ready click the "Next" button and the privileges will be updated. Regarding the System Customizer role, you can edit it manually or use again this tool, select only the role and click on "Organization" instead of "None".

After this procedure you will be able to edit again your security roles, hope it helps!

February 12, 2016

CRM 2016 Web API and plural names

The new Web API available for CRM 2016 is based on OData V4 protocol and the endpoint is /api/data/v8.0/

The MSDN contains several examples of the new endpoint, for example if we want to retrieve the top 3 accounts:

/api/data/v8.0/accounts?$select=name&$top=3

Simple, right? if you want to retrieve from account entity you write accounts, if you want to retrieve from contact entity you write contacts, if you want to retrieve from opportunity entity you write opportunities. You write the plural.

What a poor choice to use the plural form instead of the singular one, and let me say something, the root of the problem is an English-centered vision.

I'm not an expert of REST and OData protocols, maybe they suggest to use the plural forms but when you let users dynamically add entries to the endpoint (i.e. creating an entity) the use of plural forms is a mess.

A user on Dynamics Community asked a question: "my custom entity name is xxx_settings and I can't query using the endpoint /api/data/v8.0/xxx_settingss, which is the right syntax?"

Well, in this case the answer is simple, who designed the API decided to apply the exceptions, so if the noun ends with s the plural is es, in the user's case the correct endpoint is /api/data/v8.0/xxx_settingses, but if you want to be sure about the name you can check the metadata at this url: /api/data/v8.0/ or download the XML from the Developer Resources inside CRM UI.

Now let's play a game, how much are robust the exceptions they implemented in order to create the plural form? The answer is weak.
English is not my first language so I googled "plural exceptions english" and I landed in this page: A handout on irregular plural noun forms. I started to create some custom entities, here some results:
new_city become new_cities, English correct.
new_wolf become new_wolfs, English incorrect.
new_knife become new_knifes, English incorrect.
new_man become new_mans, English incorrect.

Now, I don't expect that all the irregular forms are covered, but if you decide to handle the final 's' and the final 'y' why not handle the final 'f'? However not big deal, You check the metadata and you can find the exact plural word to use.

BUT, and there is a BUT

Let's say we created our custom entity new_city and now the REST endpoint responds to /api/data/v8.0/new_cities, what will happen if we create a custom entity called new_citie?
The entity is not listed inside the REST endpoint!!! because the plural of new_citie is new_cities but it's already used by new_city.
The lesson is: pay attention when you name your entities if you need to query them using the new REST endpoint, if the plural form of a new entity is the same of the plural form of a previous entity, you can't query it.

January 7, 2016

Pay attention to the CRM version when using the SDK NuGet packages

Microsoft publishes the CRM SDK DLLs also as NuGet packages, you can find the list by browsing the crmsdk profile:

https://www.nuget.org/profiles/crmsdk

Because the packages are not separate by CRM version (for example a package for CRM 2015 and a package for CRM 2016) Microsoft simply updates the NuGet package increasing the version.
This can be an issue in some projects as happened to me some days ago. I was working on a plugin for CRM 2015, my project was targeting .NET 4.5.2 and I installed the current version of CoreAssemblies (8.0.1).
The build was successful but the plugin always returned the exception "Value cannot be null".

I spent some time to understand that the problem was the referenced DLL version, so I removed the NuGet package and I installed the 2015 specific version (7.1.1) using the Package Manager Console:

Install-Package Microsoft.CrmSdk.CoreAssemblies -Version 7.1.1

After the plugin worked like a charm.
As reference these are the current versions and the suggested .NET framework to use:
  • CRM 2011: 5.0.18 (.NET 4.0)
  • CRM 2013: 6.1.1 (.NET 4.0)
  • CRM 2015: 7.1.1 (.NET 4.5.2)
  • CRM 2016: 8.0.1 (.NET 4.5.2)