October 24, 2013

Dynamics CRM 2013 Mobile Apps (tablet and smartphone)

October 5, 2013

Get the current user inside a Workflow

Inside CRM 2011 Process editor it's not possible to get the current user, in some cases a reference can be necessary (specially for automated workflows) in order to set the right user when the workflow is used to create or assign records.
A Custom Workflow Activity can be created for this purpose, taking advantage of the InitiatingUserId property.
using System;
using System.Activities;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;

namespace WFUtils
    public class GetCurrentUser : CodeActivity
        [Output("Current User")]
        public OutArgument<EntityReference> CurrentUser { get; set; }
        protected override void Execute(CodeActivityContext context)
            IWorkflowContext workflowContext = context.GetExtension<IWorkflowContext>();
            CurrentUser.Set(context, new EntityReference("systemuser", workflowContext.InitiatingUserId));

After the Custom Activity is deployed using the Plugin Registration Tool, a new step is available

and the output parameter (Current User) can be used inside other steps

July 16, 2013

How to bind a function to the Sub-Grid refresh event

A common customization requested by customers is to execute some logic when a Sub-Grid is refreshed. Unfortunately the Xrm Object Model doesn't provide a method to bind a function to the refresh event.
To implement this functionality is necessary to use unsupported JavaScript code, paying attention when a new rollup is released.
The following code is compatible with UR12/Polaris update that introduced cross-browser support for CRM 2011.
function AddEventToGridRefresh(gridName, functionToCall) {
   // retrieve the subgrid
   var grid = document.getElementById(gridName);
   // if the subgrid still not available we try again after 1 second
   if (grid == null) {
       setTimeout(function () {AddEventToGridRefresh(gridName, functionToCall);}, 1000);
   // add the function to the onRefresh event
Is possible to use the AddEventToGridRefresh function in two different ways. Assuming to attach the following function:
// function used in this example
function AdviseUser() {
   alert("Sub-Grid refreshed");
The function can be called directly passing the parameters inside the dialog box

or inside another JavaScript function:
function OnLoad() {
   AddEventToGridRefresh('accountContactsGrid', AdviseUser);
The first parameter is a string and quotation marks are necessary, the second parameter is the name of the function and must be written without quotation marks.

July 9, 2013

Set Account's Primary Contact as Recipient when creating a new Phone Call

When a new Phone Call is created starting from an Account, the default recipient is the Account itself.
If we want to set the Primary Contact of the Account as Recipient, we need to call the following function inside the OnLoad event of the Phone Call entity.
function ChangePhoneCallRecipientFromAccountToPrimaryContact() {
    // check if is a new phone call
    if (Xrm.Page.ui.getFormType() == 1) {
        // get the Phone Call To Recipient
        var to = Xrm.Page.getAttribute("to").getValue();
        // if the Recipient is an account we continue
        if (to != null && to[0].entityType == "account") {
            // get the account Id
            var accountId = to[0].id;    
            // get the right url for the OData Query
            var serverUrl;
            if (Xrm.Page.context.getClientUrl !== undefined) {
                serverUrl = Xrm.Page.context.getClientUrl();
            } else {
                serverUrl = Xrm.Page.context.getServerUrl();
            // build the request
            var ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc"; 
            var accountRequest = new XMLHttpRequest();
            accountRequest.open("GET", ODataPath + "/AccountSet(guid'" + accountId + "')", false); 
            accountRequest.setRequestHeader("Accept", "application/json"); 
            accountRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            // execute the request
            if (accountRequest.status === 200) {
                var retrievedAccount = JSON.parse(accountRequest.responseText).d;
                // retrieve the primary contact of the account
                var primaryContact = retrievedAccount.PrimaryContactId;
                // if there is a primary contact we set as new To Recipient
                if (primaryContact.Id != null) {
                    var newTo = new Array();
                    newTo[0] = new Object();
                    newTo[0].id = primaryContact.Id;
                    newTo[0].name = primaryContact.Name;
                    newTo[0].entityType = primaryContact.LogicalName;
            else {

June 28, 2013

OptionSet JavaScript Helper Library

Xrm.Page object provides several methods to work with OptionSet attributes, the most used are:
  • Xrm.Page.getAttribute("optionset").getValue() - returns the selected item value
  • Xrm.Page.getAttribute("optionset").getText() - returns the selected item label
Sometimes is necessary to access all the items of an Optionset and not only the selected one, for this purpose I wrote a JavaScript library.

The library uses only supported JavaScript and doesn't query the metadata to retrieve the labels. It contains the following functions:

  • opt.GetValues(fieldName)
    returns an array with all the values of a specific OptionSet
    var freightTermsValues = opt.getValues("address1_freighttermscode");
    alert("Values inside Freight Terms OptionSet: " + freightTermsValues);
  • opt.GetLabels(fieldName)
    returns an array with all the labels of a specific OptionSet
    var shippingMethods = opt.getLabels("address1_shippingmethodcode");
    alert("Available Shipping Methods: " + shippingMethods);
  • opt.GetLabel(fieldName, value)
    returns the corresponding label for a specific OptionSet value
    var paymentTermLabel = opt.getLabel("paymenttermscode", 2);
    alert("Payment Term with Value 2 is: " + paymentTermLabel);
  • opt.GetValue(fieldName, label)
    returns the corresponding value for a specific OptionSet label
    var primaryValue = opt.getValue("address1_addresstypecode", "Primary");
    alert("Value for address type Primary is: " + primaryValue);
Library code:
if (typeof (opt) == "undefined") { opt = {}; }

opt.getValues = function (fieldName) {
    var values = [];
    var attribute = Xrm.Page.getAttribute(fieldName);
    if (attribute != null && attribute.getAttributeType() == "optionset") {
        var options = attribute.getOptions();
        for (var i in options) {
            if (options[i].value != "null") values.push(options[i].value * 1);
    return values;

opt.getLabels = function (fieldName) {
    var labels = [];
    var attribute = Xrm.Page.getAttribute(fieldName);
    if (attribute != null && attribute.getAttributeType() == "optionset") {
        var options = attribute.getOptions();
        for (var i in options) {
            if (options[i].value != "null") labels.push(options[i].text);
    return labels;

opt.getLabel = function (fieldName, value) {
    var label = "";
    var attribute = Xrm.Page.getAttribute(fieldName);
    if (attribute != null && attribute.getAttributeType() == "optionset") {
        var option = attribute.getOption(value);
        if (option != null) label = option.text;
    return label;

opt.getValue = function (fieldName, label) {
    if (label == "") return null;
    var value = null;
    var attribute = Xrm.Page.getAttribute(fieldName);
    if (attribute != null && attribute.getAttributeType() == "optionset") {
        var options = attribute.getOptions();
        for (var i in options) {
            if (options[i].text == label) return options[i].value * 1;
    return value;
Note: developed with Xrm JavaScript Dojo

June 26, 2013

Book review: Microsoft Dynamics CRM 2011 Cookbook

These days I got the chance to read Microsoft Dynamics CRM 2011 Cookbook, a book written by Dipankar Bhattacharya.
Microsoft Dynamics CRM 2011 Cookbook
The book has 10 chapters and is structured as a list of recipes, covering different arguments about Dynamics CRM.

Chapter 1: Installing Dynamics CRM 2011
This is the largest chapter, it not only covers the installation of Dynamics CRM Server but also other components such as Reporting Extensions, E-mail Router, Outlook Client. Step by step instructions and appropriate screenshots.

Chapter 2: Maintaining and Optimizing Microsoft Dynamics CRM 2011 Server
A basic knowledge of SQL Server is required for this chapter, especially for the Backup & Recovering part, useful the sections explaining how to enable tracing.

Chapter 3: Administering Microsoft Dynamics CRM 2011
The first three recipes assist the users to configure SSL, Claims-based authentication (AD FS) and Internet-facing Deployment (IFD), the other recipes describe how to manage business unit, users and security roles.

Chapter 4: Data Management
This chapter goes through importing and exporting data, a nice addition the section about Auditing.

Chapter 5: Solution Management
Explain (and implementing) Dynamics CRM Solutions isn't an easy job, probably a book can be written regarding this argument. The author gives a good overview, introducing also the translation process.

Chapter 6: Entity Customizations and Chapter 7: Form and View Customizations
These 2 chapters explain how to customize CRM, the concepts inside are deeply connected (you can customize CRM without installing it, but you can't customize forms and views without a good knowledge about fields and relationships). The content can look obvious to a Dynamics CRM developer, but it contains tips about Rollup Update 12 and the new Process Driven Forms.

Chapter 8: Site Map and Ribbon Customizations
The chapter describes how to edit the Site Map and Ribbon Definition XML, actually there are several tools that can be used to perform these modifications, but these pages can be considered a good reference.

Chapter 9: Office and SharePoint Integration
Well, I don't face SharePoint integrations every day, so probably next time I will use this recipe to guide me. The chapter covers also the Mail Merge functionality, both arguments are very interesting.

Chapter 10: Processes
The final chapter is the real surprise of this book. Workflows and Dialogs are very powerful and inside these pages are well explained. This part is a must-read also for end users who create or maintain processes in their CRM.
Note: the chapter doesn't cover the creation of Custom Workflow Activities.

Final score

Final Thoughts
A technical book is not a romance, this means skipping chapters or read over and over again the same pages. The variety of the arguments makes the book interestng for those who want to expand their knowledge about Dynamics CRM (a developer curious about the installation process) but also for those who face Dynamics CRM in the early stages of a project.

Where to buy