CRM 2013 – Client API: Save & Refresh

I know these operations seem like very basic functionalities that have been around for a while. I wanted to point a specific new feature that comes with CRM 2013: the ability to run a callback method after a refresh or after a save triggered from a JavaScript method.

In the past, using the old Xrm.Page.data.entity.save method caused a refresh of the page which dismissed any code after the save in your script. Take this scenario for example…

  • You have button in your ribbon on an Account form
  • The button calls an external web service to update some of the account field values based on the account’s Primary Contact value which is on editable on the form
  • The web service only takes the account id as a parameter, it loads the records, reads it and takes action

With the old save method, you had to require that the user saves the account so that the value of Primary Contact is saved to the database, then click your button that will call the web service with account ID. Such a requirement certainly causes pain in user experience especially if there are a lot of situations where they need to hit save, wait for refresh and click another button.

With the new Save and Refresh, we now have the possibility to add callback methods:

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

// Parameters
// save => A Boolean value to indicate if data should be saved after it is refreshed.
// successCallback => A function to call when the operation succeed
// errorCallbak => A function to call when the operation fails. It gets called with 2 parameters (an error code and a localized error message)

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

// Parameters
// successCallback => A function to call when the operation succeed
// errorCallbak => A function to call when the operation fails. It gets called with 2 parameters (an error code and a localized error message)

Having had this problem in the past makes this one a good candidate for most exciting new client API feature for me 🙂

Cheers

CRM 2013 – Client API: Dialogs

CRM 2013 introduces a couple of client side dialog methods under the Xrm.Utility library. The goal is to remove the use of window.open and window.confirm and replaces them with alertDialog and confirmDialog and to support these alert messages in CRM for Tablets. Also, the key difference is that these methods will not block code until a user closes them. However, they contain a callback function parameter to indicate what code should be executed depending on the user’s response.

The Xrm.Utility.alertDialog(message,onCloseCallback) method displays a dialog box that contains a message passed as a parameter. Optionally, you can also execute another method (onCloseCallback) when the OK button is clicked.

var message = "Alert Dialog ! ";
 Xrm.Utility.alertDialog(message, onCloseCallback);
 

The Xrm.Utility.confirmDialog(message, yesCloseCallback, noCloseCallback) method displays a confirmation dialog box that contains an optional message and an OK and a Cancel button. A callback method can be set to run after each of the button is clicked.

var message = "Confirmation Dialog ! ";
 Xrm.Utility.confirmDialog(message, null, null);
 

Again in this case, the methods are only available for “Updated Entities”. You can see my previous post to get the list of entities on which this will not work.

Cheers

CRM 2013 – Client API: Client Methods

The CRM 2013 client API adds a few useful methods. Here I am going to focus on the context.Client methods : context.client.getClient() and context.client.getClientState. These methods are used to find out what kind of client is running and to get the information about it being online or offline. This is useful if you have scripts that you want to run when you are in the web application and nowhere else (not in Outlook client, not on Mobile client). As a consequence of this API change, the previous context.IsOutlookOnline and context.IsOutlookClient are now deprecated.

The getClient method returns the value Web (browser), Outlook (Outlook client) or Mobile (mobile app). The getClientState method returns Online or Offline, the latter applying only to the Outlook and Mobile clients. It’s also worth noting that these methods are only available for what Microsoft calls “Updated Entities”. In short, it’s the entities that have an updated interface (most key entities like Account, Case, Contact, basic activities like Phone Call, Tasks fit into that category). It also works on custom entities.

The entities that are not updated still use the “classic forms” and the Client methods are not supported on these. Here is the list of the entities with classic forms:

Address
Article
Article Comment
Bulk Delete Operation
Connection
Discount
Discount List
Document Location
Email Attachment
Follow
Goal
Goal Metric
Import Source File
Invoice Product
Order Product
Price List
Queue Item
Quote Product
Rollup Field
Rollup Query
Saved View
Service
Service Activity
SharePoint Site
Site
Territory
Unit
Unit Group

CRM 2013 – Real Time Workflows

In the CRM 4.0 and 2011 days, I remember multiple times when I had to write plugins do to operations that a simple workflow could do just because it needed to happen synchronously. Microsoft brought a solution to that concern with the latest CRM 2013 release by introducing real-time workflows.

In order to create an asynchronous workflow, you simply need to create a workflow and uncheck the “Run this workflow in the background (recommended)” checkbox.

If you have missed it or are trying to covert an Asynchronous workflow into a synchronous one, you can do it by deactivating the workflow and using the “Convert to real-time workflow” button.

The workflows’ contents are the same. There is no additional operation that you can do in real-time. The one thing that changes is the way you set up when the workflow gets triggered. Just like when plugins are registered, you have the possibility to choose if you want them to execute before or after a specific event:

Background Process Real Time Process

A few key notes on Real-Time Processes:

  • They can run
    • After record creation
    • Before or after a record update, assignment or status change
    • Before record deletion
  • They can be set to run as the owner of the workflow or as the person making changes to the record in CRM

It certainly gives us more flexibility when it comes to designing feature for real day to day usage. One thing still makes me wonder… Microsoft seems to recommend using background processes. Assuming the reason for that recommendation is performance, I guess it is a way to let application designers know that even though workflows can be run in real-time, this should only be used when really needed as opposed to making it a standard and clogging the CRM Server. To be confirmed…

Cheers

Managing CRM User Roles Programmatically

You often hear CRM users and admin complain about having to manage the system users’ roles too often. It can be a pain if you have a lot of movement in the company, for example people going from one business unit to another, high turnover rate or fast growing company.

I thought I would share a design idea for making user management a little bit easier for your organization. It consists of a few steps, and it requires some coding skills.

  • Define your business roles and match each of them to a set of CRM Security Roles.
Business Role CRM Security Roles
Sales Manager SalesPeron; Sales Manager
IT Manager System Customizer
  • On the “User” entity, create an Option Set field representing the business roles capture in step 1

Now the fun begins.

  • Create an XML file to map the business role option set values to a set to CRM Security Role names (see XML format in picture below)
  • Upload the XML file to CRM as a web resource
  • Switching over to the plugin side. You need to build a plugin that runs on update of a User record and that that does the following operations:
    • Read the “Business Role” field value on the User record
    • Retrieve the web resource configuration XML file based on its name or ID
    • Parse the XML to get the CRM roles corresponding to the business role selected
    • For each CRM Security Role found, assign it to the user
    • This is what my plugin code looks like:
public override void Execute(IExecutionContext context, IOrganizationService service, ITracingService tracingService)
{
 if (context.MessageName != "Update") return;

if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
 {
 Entity target = (Entity)context.InputParameters["Target"];
 if (target.Attributes.Contains("sa_userrole") && target.Attributes["sa_userrole"] != null)
 {
 SystemUser user = target.ToEntity<SystemUser>();

// Get Security Roles from Configuration
 WebResource wr = GetWebResourceByName(WebResourceName, service);
 string xmlContent = UnicodeEncoding.UTF8.GetString(Convert.FromBase64String(wr.Content));

XmlDocument config = new XmlDocument();
 config.LoadXml(xmlContent);

XmlNodeList crmRoles = config.SelectNodes("/SystemRoles/SystemRole[@ID=" + user.sa_UserRole.Value + "]/Role");
 foreach (XmlNode role in crmRoles)
 {
 Role crmRole = FindSecurityRole(user, role.InnerText, service);
 AssignSecurityRole(crmRole, user, service);
 }
 }
 }
}

/// <summary>
/// Retrieves a CRM Web resource by name
/// </summary>
private WebResource GetWebResourceByName(string webResourceName, IOrganizationService service)
{
 QueryByAttribute requestWebResource = new QueryByAttribute
 {
 EntityName = WebResource.EntityLogicalName,
 ColumnSet = new ColumnSet(true),
 };
 requestWebResource.Attributes.AddRange("name");
 requestWebResource.Values.AddRange(webResourceName);

EntityCollection webResourceCollection = service.RetrieveMultiple(requestWebResource);
 return (WebResource)webResourceCollection.Entities.FirstOrDefault();
}

/// <summary>
/// Find a Security Role by name and business unit
/// </summary>
private Role FindSecurityRole(SystemUser user, string roleName, IOrganizationService service)
{

if (user.BusinessUnitId == null || user.BusinessUnitId.Id == Guid.Empty)
 {
 SystemUser retrieveUser = service.Retrieve(user.LogicalName, user.Id, new ColumnSet("businessunitid")).ToEntity<SystemUser>();
 user.BusinessUnitId = retrieveUser.BusinessUnitId;
 }

// Retrieve a role from CRM.
 QueryExpression query = new QueryExpression
 {
 EntityName = Role.EntityLogicalName,
 ColumnSet = new ColumnSet("roleid"),
 Criteria = new FilterExpression
 {
 Conditions =
 {
 new ConditionExpression
 {
 AttributeName = "name",
 Operator = ConditionOperator.Equal,
 Values = {roleName}
 },

 new ConditionExpression
 {
 AttributeName = "businessunitid",
 Operator = ConditionOperator.Equal,
 Values = { user.BusinessUnitId.Id }
 }
 }
 }
 };

return service.RetrieveMultiple(query).Entities.Cast<Role>().FirstOrDefault();
}

/// <summary>
/// Assign Security Role to a CRM User
/// </summary>
private void AssignSecurityRole(Role securityRole, SystemUser user, IOrganizationService service)
{
 service.Associate("systemuser",
 user.Id,
 new Relationship("systemuserroles_association"),
 new EntityReferenceCollection() { securityRole.ToEntityReference() });
}

At this point, all you have to do is change that field on your users’ form and the plugin will handle assigning the security roles automatically. You may want to implement a way to handle the security roles assigned to users before the business role is changed. If you are planning to use this design or something similar, here are some key takeaways:

  • The same logic cannot be processed at the creation of the “User” record. That is because before being able to assign security roles to a user, the system needs additional information that gets created after the user record is created.
  • The plugin must run as an administrator or a user who has enough privileges to create and assign security roles to a user
  • The configuration is stored in a XML web resource but it could be stored anywhere (CRM entity, external database, flat file etc.)
  • Also note that Security Roles are copied to each business unit, so when looking a Security Role in CRM based on its name, it is important to search in the same business unit as the user’s
  • CRM does not allow to edit multiple user records at the same time

Have fun with this!

Microsoft Dynamics CRM Data Archiving Solutions

As Dynamics CRM consultants, one of the questions that we often get from clients is “how do we archive CRM data when it’s no longer needed”? I’ve seen companies that had to keep all of their data for a certain amount of years for legal reasons. In any case, if you are using Dynamics CRM as a service management tool for a busy call center for example, chances are you are creating a LOT of records at a very fast pace. Imagine having to retain all of the data you created in the past 5 to 10 years on the same system. The size of the database can grow to become extremely large, making every single query a long one and impacting directly the users experience and their trust in the system.

Before I go into details about the available options that I can talk to, here is a quick recap of what Microsoft officially said a while ago about archiving Dynamics CRM data.

  1. Archiving implies moving records from one location, storing those records for possible retrieval in another location, and deleting the archived records from the original location.” Given the complexity of the relationships in CRM, archiving as defined in the previous sentence can be very risky and must imply extensive thought, design and knowledge of the CRM application and database.
  2. An arching solution should not be implemented with the goal of improving system performance.
  3. Instead of deleting records, it is recommended to deactivate them when they are no longer required.
  4. The Dynamics CRM application can support very large databases, it is important to make sure that the hardware and database are configured in order to get optimal performance before looking at Archiving.

Here are some possible approaches that can be used to archive your Microsoft Dynamics CRM data. Before going down that path, make sure this is something you really need, don’t just build an archiving solution because you want to improve your system performance. Do your homework first!

Archiving Method How it work Pros Cons
1 – Create a copy of the database It requires a strong DBA with knowledge of the CRM database to make a copy of the DB, copy all the records that need to be archived to the new DB and finally delete them from their original location. Sounds easy for a DB expert I assume (I’m not!)
  • It’s one of the less expensive solution as it only requires a strong DB developer with knowledge of CRM and an available SQL Server database
  • Not supported nor recommended by Microsoft
  • A DBA with knowledge of the Dynamics CRM database is always required to retrieve data from the archive database
2 – Create a new instance of Dynamics CRM
  • Create new organization or new CRM installation and install the same solution as the one in production
  • Create a mechanism to copy records from the production environment to the new archiving organization and delete them from their original location. This can be done with :
    • A custom .NET application using the CRM SDK
    • Scribe, Microsoft’s CRM 2011 Instance Adapter or other third party providers routines
    • Database scripting (unsupported)
  • The archived records are easy to retrieve (same UI as prod)
  • Access to these records can be controlled by the Dynamics CRM security model
  • Can be done in a supported way
  • Expensive solution that may requires additional hardware, server and/or user licenses for CRM or SQL Server
  • Company ends up maintaining more than one CRM organizations in the long run
3 – Deactivated unwanted records and tweak database Indexes
This is easily the number 1 choice from Microsoft’s perspective. To me, this should be one of the drivers in the CRM application design. The lifecycle of all records that are created (except for master data) should always be to:

  • create record (with active state obviously)
  • do work
  • deactivate record after the job is complete (set state to inactive)

In many systems that I have seen, some records just remain active forever, even though they are old and on longer required in the active records view.

Also, it is important to create SQL indexes to enable a faster retrieval of active records.

 

  • This method does not involve the deleting on any record from the CRM database which is what MS recommends
  • It forces the application to be designed with best practice for records lifecycle management
I could write down that the down side is that records remain in the CRM database but again, you are not archiving simply because you want to reduce the size of your database…
4 – Create and store custom archive reports This is an interesting one. I’ve personally recommended using this solution to capture the history of successful workflows execution prior to deleting them from the system.
The idea is to create custom reports containing information from the records that are no longer needed in the system. Once the reports have been created, they can be stored in a document management system or sent by email. After that, then the records can be deleted from the CRM database.
There are many ways to create reports in CRM so I won’t spend time discussion that topic here. A simple Google (or should I say Bing searchJ) will give you plenty of starting points.
  • Lots of options for reports creation and execution (3rd party software, SSRS, scheduling jobs, custom workflow activities etc.)
  • Can be done in a supported way
  • What used to be CRM records are now lines of text in different reports
  • Records must be saved in a managed location (example: doc management system with redundancy instead of external hard drive for the system admin…)
  • Access to the reports must be controlled
  • Ability to search for archived information can be limited and/or very painful in flat files
  • Building the reports can be expensive :
    • Report design can take time
    • Development cost depends on the tool used (SSRS, 3rd party…)
5 – Create a custom Archive Database
This is very similar to option 2. The difference would be instead of creating a new instance of CRM, you can create a custom database where you would only keep the information that you need. This database would be populated by a custom .NET app, third party data migration tool routine or database scripting.
Optionally, a custom UI can be developed to enable administrators to search through the custom database.
  • Tailored archiving solution, enables for more granularity and focus on retaining only the information that is required
  • If done well and if CRM solution(s) doesn’t evolve too much over time, it’s a one effort and maintenance should be easier than maintaining 2 CRM instances
  • Can be done in a supported way
  • Expensive to build (requires deep analysis and development time)
  • Custom database must be maintained
  • Security is no longer controlled by the Dynamics CRM application

I personally like solution 5 better but it’s only because I’m a developer and I’d enjoy having to design the new database and the archiving tool. Of course, every company has its own preferences and resources with different set of skills. This should all be taken into consideration prior to deciding what solution to use. These are only the ones that I came up with, there are certainly other options out there.

Hope this helps!