How to show SharePoint document list on main CRM form

When you enable the SharePoint integration for CRM, you get the ability to view a document list view by navigating to the document area on the form. Often, users want have this list of document available directly on the main form and not have to navigate to another page. Here is one way to do it, applicable for the “old fashion” SharePoint integration using the SharePoint List Component for CRM. It does not apply to server-based SharePoint integration with CRM. This is an unsupported customization, use at your own risk. 

What you need

  • SharePoint integration enabled and configured for the target entity (i.e. list component installed, existing SharePoint Site & folder)
  • an IFrame on the form
  • a way to get the full URL of SharePoint folder associated to your record (could be a field that you automatically populate on the entity with a plugin, could be retrieving the SharePoint Document Location records using JavaScript when for form loads, etc.)

How it works

When the document view is loaded, there is a URL pattern used by the system to display the list component with the documents:

http://sharepointdev/crm/crmgrid/crmgridpage.aspx?langId=en-US&locationUrl={document location url}&pageSize=250

What you can deduct from the URL above:

{SharePoint Root Site}/crmgrid/crmgridpage.aspx?langId={Language}&locationUrl={Document Location Url}&pageSize={Page Size}

Grabbing that Url with the correct parameters and pasting in browser will display the list of document for the target CRM record. In short, all you have to do is display that Url constructed properly inside an iFrame on your CRM form (see illustration below). Please note that this can have a performance impact on how quickly the form loads (this component can take longer to be loaded and displayed.

image

Code snippet

Javascript Method to load the content


var documentSiteUrl = ""; /* Find a way to get this information – can be read from a hidden field on the form. */
var parentSite = ""; /* Find a way to get this information – can be read from a hidden field on the form. */

if (documentSiteUrl == "" || parentSite == "") {
   return;
}

// Build document location URL - Set IFRAME target
var docViewUrl = parentSite;
if (!StrEndsWith(docViewUrl, "/")) {
   docViewUrl = docViewUrl + "/";
}

var userLanguage = "en-US";
if (Xrm.Page.context.getUserLcid() == "1036") {
   userLanguage = "fr-FR"
}

docViewUrl = docViewUrl + "crmgrid/crmgridpage.aspx?langId=" + userLanguage + "&locationUrl=" + documentSiteUrl + "&pageSize=250";

var documentIFrame = Xrm.Page.ui.controls.get("IFRAME_Documents");
if (documentIFrame != null) {
   Xrm.Page.ui.tabs.get("Documents").setVisible(true);
   documentIFrame.setSrc(docViewUrl);
}
else {
   Xrm.Page.ui.tabs.get("Documents").setVisible(false);
}

EditAble CRM Grid by AbleBridge

I recently spent some time trying out the AbleBridge EditAble CRM Grid for Microsoft Dynamics CRM 2013. In this article, I’m providing an overview of the product that can help you make an informed decision if you are looking for a rich data grid experience for your Dynamics CRM implementation.

Installation

AbleBridge EditAble CRM Grid can be installed in CRM Online and On Premise. There are two main steps to install the add-on.

  1. CRM Solutions

    There are 2 CRM solution files to import (Core & Data Grid) to your organization.

  2. License Configuration

    Once the solution files have been imported, a license XML file must be generated by AbleBridge. It contains a key that’s tied to your organization and customer, it also brings in information such as user count and expiration date.

Solutions Components

The solutions files (Core & Data Grid) are very small (less than 1.5 MB combined) and they import very quickly, showing how lightweight the add-on is.

The Data Grid solution contains around 150 components, mostly web resources (images, javascript and HTML), some plugin steps and a few CRM entities. As you can see in the screenshot in the previous section, the configuration screen is HTML/JavaScript based, not Silverlight as we’re accustomed to see with CRM add-ons. The entire solution is actually HTML/JavaScript based, there is not a single trace of Silverlight in the solution which personally makes me very happy J.

EditAble CRM Grid Configuration

After the solutions have been imported, you can navigate to the Settings àAbleBridge Data Grid list view to take a look at the existing EditAble CRM Grids or create new ones.

To create a new EditAble CRM grid, create a new Data Grid Configuration record. Doing so will take you to a wizard that will guide you through the configuration steps of your view. The basic steps are

  • Grid basic configuration information
    • Grid name
    • Entity to show in the grid
    • Grid “mode” (Editable or Read Only)
  • Columns Selection & Configuration

  • Record Selection setup: select whether you want records to be shown based on a specific filter (entity list view) or related to a parent record (child entity sub-grids)

Notice that at step 2 above (add and configure columns), we do not get the option to add columns from related entities. When using the AbleBridge EditAble CRM Grid, you can get the same behaviour by configuring a custom field in the grid (not described in this article). I am told it will have more native support in a future release.

Once you have gone through the basic grid configuration wizard, you are presented with the Grid configuration record itself. It presents many more options to configure the grid. Let’s review some of the options. We’ll go through most sections of the configuration record so you can see all available config options.

Ribbon Buttons

As you can see in the image above, a few buttons have been defined and provide with the ability to

  • Refresh Grid Definition: this will take you back to the configuration wizard I talked about earlier to redefine your grid’s basic configuration
  • Publish Grid Configuration: same concept as CRM customization, a Grid Configuration needs to be published for users to see its latest configuration
  • Preview: you can preview a grid layout and functionality. This is a nice feature to allow you to make sure that your configuration is correct before publishing it.
  • Copy: used to copy a grid configuration

General Section

The available options for the general section are the row functionalities and the display options.

Grouping Section

I particularly like this feature. It can be viewed as an alternative to the out of the box dashboards that are not available with the grid. Plus if users are used to the “Group By” functionality in Excel, this gives them a very similar type of experience.

Columns Detailed Configuration

For each column, you can set additional details such as their visibility, read only, alignment and enable grouping. You can also change the column order.

Additional Options

There are more options available. I wanted to point out two options in particular

  1. Filters: like a regular CRM view, you can select filter criteria that will be applied to the EditAble CRM Grid
  2. Custom Events: you can write code using AbleBridge EditAble CRM Grid custom API. Your code can fire at different type of events (grid events, column events or toolbar button – yes you can create your own toolbar button for a grid)

Viewing the Grid

The views are web resources. They can be configured to be visible in the sitemap or as sub-grids. Below are a few examples of grid configuration.

Quick Recap

The AbleBridge EditAble CRM Grid is a very good add-on for Microsoft Dynamics CRM. Being able to edit grids inline is a feature that’s been missing in CRM for a long time and as consultant, we very often get ask to inline editing feature. AbleBridge brings that, and more.

User Interface

The user interface is good looking and light weight, all JavaScript and HTML based. The grid themselves look like OOB CRM grids and the configuration is straight forward.

Feature Set

The feature set is very rich, enabling for deep customization of the grid. A few examples are columns sizing, ordering and visibility, grouping, export to Excel. The grid respects the CRM security (security roles, teams, FLS). AbleBridge also provide the ability to write code that can be executed on various events such as grid load, refresh, column change, toolbar button clicked.

The grid currently supports four languages (English, Danish, French and German) and more can be added upon need/request.

Unfortunately, with the grid we lose the ability to have the charts displayed with the view and everything that comes with it. But grouping and calculated fields (sums, counts) are a good alternative for summarizing and filtering data. The other thing that bothered me is not having the possibility to easily add columns from related entities which is a set back from the OOB views. Finally, we faced some issues with users running IE8, we didn’t spend time fixing it and moved them to a different version. It would be interesting to know if there is an easy fix or if IE8 is not really supported.

Licensing
AbleBridge EditAble CRM Grid offers the classic two license models:

  • Monthly Subscription option (pay a monthly price per CRM org based on the number of users)
  • License Purchase option (one-time fee based on the number of users)

In addition to that, you can pay for annual maintenance which covers compatibility with supported version of Microsoft Dynamics CRM (only applies to license purchase option, included in monthly subscription model).

AbleBridge’s grid is one of the most expensive editable grid add-on for CRM in the market. I think a lot of it has to do with that fact that they came out with a zero-Silverlight based product from the beginning, understanding HTML5/JavaScript is the future (or present and future). They also offer a very rich set of features that I haven’t see in competitors’ products.

Hope this helps!

CRM 2013 – Leveraging Actions to get around JavaScript cross-domain challenges

Last year, I wrote about the challenge of cross-domain calls from JavaScript with CRM 2011. The issue was related to fact that from a security perspective, you could not have JavaScript functions executing on a CRM form event or when a ribbon button is clicked calling web services outside of the CRM domain. I proposed a few workarounds here but the bottom line is that in all cases, there was some sort of a negative impact in each solution. With CRM 2013, actions processes are a great way to get around the browsers’ cross domain restriction.

In this article, I am providing an example of how actions can be used to make a request to a web service outside of the CRM domain from a record’s form event.

Scenario

When users call an incident management center, the agents need to capture the temperature at the time of the incident in the city where it occurred. In order to do so, we decide to create a button on the command bar that agents can click on and that will perform the following tasks:

  • Read the City and Country information from the form
  • Call an Action that
    • Takes the City and Country as parameters
    • Use an external web service to get the temperature in the city
    • Returns the temperature as output parameters
  • Sets the temperature field value on the form

Note: In order to achieve this directly with JavaScript, performing Step 2 of the action would require to make a cross-domain call from JavaScript.

Process Configuration

To start things off, let’s start be creating an Action of type process. This action will have 2 input values (City and Country) and 2 output values (Temperature in Fahrenheit and in Celsius).

The steps are really simple. The action needs to a custom workflow activity that will connect to a weather web service and return the temperature in two output values of its own.

Custom Workflow Activity

Here you can see what the custom workflow activity code looks like. It’s very straight forward in that it only has 3 steps:

  1. Read the city and country inputs
  2. Initialize the web service client object and make the web service call
  3. Set the values back in the output fields to be available in the process

Calling Action from JavaScript

This is the last piece of the puzzle. At this point, we simply need to call the action created from a JavaScript event (ribbon button clicked, on change of a value etc.). In order to achieve this, create a function that is called when the client even occurs. That function should execute the Action, read the output values and set the field values on the form. This has to be done with a SOAP call. There are two ways to do this. You can:

  • use Deepak’s example as show in his blog post here or
  • use the CRM 2013 Sdk.Soap.js action message generator published by the Microsoft CRM SDK team to generate a request and response class you can use in your call to call the action using JavaScript.

Wrap up

This is another great example of how actions can be leveraged to work around challenges that we’ve dealt with in the pre-CRM 2013 era. Keep in mind that in order to call an external web service from the custom workflow activity, there are server security elements to take into consideration (e.g. can my server talk to the web service? etc.)

Hope this helps!

CRM Dev Tool for Chrome

A few days ago, Sonoma Partners released a very nice Development Tool. It comes as a Google Chrome extension and it’s compatible with CRM 2011 UR11+ and with CRM 2013. It’s a nice productivity booster for CRM developers so I thought I’d share it. Here are some of the highlights:

  • View Current User Information (domain name, user Id)
  • Form information (entity name, Id, type code and some nice features like show the hidden attributes on a form)
  • Execute Fetch XML statement and view the results

How to use it?

  • Using Google Chrome, install the app from the web store
  • Navigate to a record in CRM 2013 or 2011 UR 12+
  • Press F12 to open the Chrome DevTools Panel
  • Click the CRM DevTools tab on the far right

You can read all the details about the tool on Sonoma’s blog post.

Enjoy!

How to change a Plugin “Run in User’s Context” Programmatically

When you design Plugins for Microsoft Dynamics CRM, you sometime need to have them run as a different user in order to perform operations that a non admin user cannot normally do. This is usually done by using the Plugin Registration tool and setting the value of the “Run in User’s Context” drop down field to a specific value (see screenshot below).

Today I want to show a way to do this programmatically. Our design is fairly simple and the overall goal is to have the appropriate impersonation user being assigned to all required plugin steps automatically without manual processing post-solution import.

  • Create Plugins and steps with the Plugin Registration Tool as usual
  • The name of each plugin that requires to run as an admin user must contain a pre-defined text (in our case [Admin])
  • After each solution is imported to CRM, a plugin fires and look for all plugin steps where the name contains [Admin]
  • Updated the Run In User’s Context field with an admin user defined as per configuration

That’s easy enough. For step 4, where you store the configuration is up to you, it could be registry, XML web resource, custom entity etc.

Here is the code to do it:

Cheers

Dynamics CRM and multi-tenancy

It’s a topic that is often discussed and after Microsoft released its whitepaper on it late last year, I thought it would be interesting to write a short summary of some of the enterprise challenges that it addresses.

Definition

Let’s take a look at a few definitions of the term “Multitenancy

Multitenancy refers to a principle in software architecture where a single instance of the software runs on a server, serving multiple client-organizations (tenants).” – Wikipedia

Multi-tenancy is an architecture in which a single instance of a software application serves multiple customers. Each customer is called a tenant. Tenants may be given the ability to customize some parts of the application, such as color of the user interface (UI) or business rules, but they cannot customize the application’s code.” – WhatIs.com

Multitenancy is a reference to the mode of operation of software where multiple independent instances of one or multiple applications operate in a shared environment. The instances (tenants) are logically isolated, but physically integrated” – Gartner IT Glossary

Relating these definitions to Microsoft Dynamics CRM, we can view the CRM Server installation as the single instance of the application and the CRM Organizations created on the CRM server as tenants. The tenants are technical groupings within the application, such as separate databases within SQL Server.

Common Enterprise Challenges and Solutions based on Multi-tenancy

Function Localization

  • Description: Provide a common core of functionality, but with local functional variations – with “proper” delegation
  • Example: Multi-national company with business models that vary based on market size, legal compliance or other factors
  • Solution: Using multi-tenancy or multiple instances allows each business area or local region to have an independent implementation with its own local variations.

Master data management

  • Description: Provide a consistent, managed core of information, perhaps distributed only Selectively and enable smooth transitions without big bang replacements
  • Example: You may have an organization that operates in multiple areas and the terms/rules differ from one place to another. These different areas may need to manage their master data independently from one another. In these types of scenarios, it is important to maintain the data that is common across the different components and particularly critical is managing changes to that data. While there are different approaches for accomplishing this goal, many scenarios benefit by having a “master” for certain data sets because it provides for change management through that central master data source (master data management, or MDM)
  • Solution: This approach requires that the central master data be synchronized to all instances so that each instance has access to the latest version of the core information

Physical distribution

  • Description: Mitigate network latency
  • Example: For business solutions that support users that are physically distributed over large distances (global deployments), using a single instance may not be suitable because of the implications (such as WAN latency) associated with the infrastructure over which the users connect.
  • Solution: Distributing instances to provide users with more local access can reduce or overcome WAN-related issues, as the access occurs over shorter network connections

Security/privacy

  • Description: Accommodate legislative/national differences (e.g. patient confidentiality, Swiss banking, third-party use)
  • Example: This is usually a resulting of some sort of legal compliance. For example in Canada, healthcare patient information cannot be transferred from one province to another. If there was a national platform, there would have to be a way to prevent people from access data from patients living in other provinces.
  • Solution: In these types of scenarios, some or all of the data is stored locally, and potentially some of the data is stored centrally

Scalability

  • Description: Accommodate extreme volumes and/or extensive use of Service Scheduling; Provide for isolation of workloads (e.g. web site, customer kiosks)
  • Example: While a single instance of Microsoft Dynamics CRM can scale up and out to support the growth of a customer’s business, with very high data volumes or levels of complexity, there are additional considerations.
  • Solution: for scenarios in which groups of users work independently of each other in operational terms, it may be possible to host the groups on separate Microsoft Dynamics CRM instances and to use reporting to combine results across business areas for management oversight

Multi-tenancy Challenges and Solutions Patterns

The whitepapers has a full detailed section on possible solutions to the challenges introduced by multi-tenancy. These challenges come from the fact that the separation has to be managed. You may want to synchronize your metadata, or expose data from on CRM organization within a different organization.

CRM 2013 – Client API New Functionalities Recap

If you’ve been following, I had a series of Client API posts late last year. Below I have regrouped the new Client API functionality in a table for reference. This can become helpful especially if you are developing with the “old” CRM 2011 mindset to easily see what you can achieve differently and/or more efficiently in CRM 2013. Details on the new functionalities is available on the Microsoft Dynamics CRM YouTube video and in the CRM 2013 SDK.

Area

Method and Syntax

Description

Data

Xrm.Page.data.refresh(save).then(successCallback, errorCallback)

Asynchronously refreshes and optionally saves all the data of the form without reloading the page.

You can pass a callback method to execute on success or error

Data

Xrm.Page.data.save().then(successCallback, errorCallback)

See my blog post on this here

Data

Xrm.Page.data.getIsValid()

Returns a Boolean value indicating if the form can be saved or not

Data

Xrm.Page.data.setFormDirty()

Set the form as dirty

Entity

Xrm.Page.data.entity.getPrimaryAttributeValue()

Gets a string for the value of the primary attribute of the entity.

UI

Xrm.Page.ui.setFormNotification(message, level, uniqueId);

Xrm.Page.ui.clearFormNotification(uniqueId)

Use setFormNotification to display form level notifications and clearFormNotification to remove notifications. Gareth Tucker has a great article on these here.

Controls

Xrm.Page.getControl(fieldName).setNotification(message)

Xrm.Page.getControl(fieldName).clearNotification()

See article linked above for details. Notifications can be set at the field level

Number

Xrm.Page.getAttribute(fieldName).setPrecision(precision)

This method is used to override the field’s precision

Date

Xrm.Page.getControl(arg).setShowTime(bool)

Specify whether a date control should show the time portion of the date.

Date

Xrm.Page.getControl(arg).setIsAllDay(bool)

Specify whether a date control should set a value including the entire day.

Lookup

Xrm.Page.getControl(arg).addCustomFilter(filter, entityLogicaName)

Use add additional filters to the results displayed in the lookup. Each filter will be combined with any previously added filters as an ‘AND’ condition

The entity logical name is optional. If this is set the filter will only apply to that entity type. Otherwise it will apply to all types of entities returned.

Lookup

Xrm.Page.getControl(arg).addPreSearch(handler)

Use this method to apply changes to lookups based on values current just as the user is about to view results for the lookup.

The argument is a function that will be run just before the search to provide results for a lookup occurs. You can use this handler to call one of the other lookup control functions and improve the results to be displayed in the lookup.

Lookup

Xrm.Page.getControl(arg).removePreSearch(handler)

This API call is used to remove event handler functions that have previously been set for the PreSearch event (see above)

Context

Xrm.Page.context.getUserName()

Returns the name of the current user.

Context

Xrm.Page.context.client.getClient()

Xrm.Page.context.client.getClientState()

See my blog post about it here

Utility

Xrm.Utility.alertDialog(message,onCloseCallback)

Xrm.Utility.confirmDialog(message,yesCloseCallback,noCloseCallback)

Displays a dialog box containing an application-defined message.

Displays a confirmation dialog box that contains an optional message as well as OK and Cancel buttons.

See additional notes on this here.

Utility

Xrm.Utility.isActivityType(entityName)

Determine if an entity is an activity entity.

Utility

Xrm.Utility.openEntityForm(name,id,parameters)

Opens an entity form. Parameters are optional and used to pass the form ID, set default field values or pass custom query string parameters

Utility

Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)

Opens an HTML web resource.

Dynamics CRM – Year Review from my notes…

2013 has been a huge year for us all Microsoft Dynamics CRM professionals. I thought I would take a few minutes to review my blog stats and make a quick review of what has been helpful to people in the communities over the past 12 months.

The CRM development tools is one of the most popular. The idea back then was to build a CRM Solutions deployment utility to help support a development environment that resembles what MVP Gonzalo Ruiz describes on his blog post. With time, this had become a fairly popular tool available on Codeplex and I’ve received a lot of feature requests. Obviously, with all the time that I have, I was able to integrate… almost none of them J. Hopefully, 2014 will be a better year.

The other very popular article is the one about MSCRM and data archiving. It is something that almost every client will ask for prior to buying a CRM solution and there still isn’t a straight answer. It always depends on why you need to archive, how much money you want to spend on it and who is going to do the job for you. With CRM 2013 coming out and SQL 2012, I may dig into some of the new performance metric and write an update on that topic over the next year.

The CRM 2013 Client API series has been a success as well.

For 2014, I am planning to start by writing a more concise article that highlights the changes in the CRM 2013 APIs including client and server operations. I will also spend some more time evaluating ISV solutions which I cannot wait to get my hands on. In the meantime, enjoy the holidays my CRM people!

Cheers!

CRM 2013 – Client API: Save Event Arguments

There are a few useful additions that have been added to the client API around the Save event. They are 3 methods that have been formally introduced:

getSaveMode: Returns a value indicating how the save event was initiated by the user.
isDefaultPrevented: Returns a value indicating whether the save event has been canceled because the preventDefault method was used in this event hander or a previous event handler.
preventDefault: Cancels the save operation, but all remaining handlers for the event will still be executed.

The key method is the getSaveMode function. Think about the new auto-save feature on updated forms. The getSaveMode function allow the javascript method executing on the Save event to know why/how the record is being saved. That gives you the flexibility as a developer to add some additional logic to handle your scenario… Below is the list of values returned by the getSaveMode function based on the entity type.

Entity Event Mode Value
All Save 1
All Save and Close 2
All Save and New 59
All AutoSave 70
Activities Save as Completed 58
All Deactivate 5
All Reactivate 6
User or Team owned entities Assign 47
Email (E-mail) Send 7
Lead Qualify 16
Lead Disqualify 15

This is fantastic as you can now write script to handle very specific scenario like an activity being resolved, a record being saved and closed, assigned and other cases. Below is a usage example in which we prevent the auto-save from happening as presented in the SDK documentation:

function preventAutoSave(econtext) {
   var eventArgs = econtext.getEventArgs();
   if (eventArgs.getSaveMode() == 70) {
      eventArgs.preventDefault();
   }
}

Cheers