CRM 2011 online Performance and Read only forms

I attended a performance session at convergence today and finally MSFT has heard all those who have been complaining about the CRM online slow performance. I do not know is this would solve the issue or not but at least it is a step in the right direction. In a couple of weeks they will release Read Only (RO) forms. We saw the demo today and it does load fast. So administrator can enable the RO forms for users and then they will have the option to change the default form back to the one that is editable in personal preference section. However if there is any client side scripting then the RO form would not work. Although pretty lame yet I believe it is a step in the right direction. I had a discussion with their product team and they said they would work on in it in future release to analyze if they consider making it work with client side scripting but I am sure it wont be without tweaks from developers on client side. RO form does not have Ribbons so I think that is the most important piece for the performance gain. They have not changed anything on the server side as one would expect. It is just the client side form loading process that has changed. I shared with them that if users could have option to load form without ribbon or have buttons instead of ribbons that would serve the purpose better. Anyways I believe they are considering performance gains now and this is certainly very important.

They also shared a performance tool for CRM online that I must confess at least I did not know about. It can be accessed using following address

https://YOURORG/tools/diagnostics/diag.aspx. It is a nice to tool to check latency and Bandwidth. I have been using various methods to do this in the past not knowing that they have this very nice utility available. Will keep you posted with further updates.

Updated 03-28-2012

Just wanted to share that with Roll-up 7 Read only forms are now available.

http://support.microsoft.com/kb/2600643

MSDN link:

Entity Display Name

I have seen many questions on “how can one get the entity display name” in CRM. Entity display name is the name displayed on the form and not in schema. For example the display name for ‘bulkoperation’ entity is ‘Quick Campaign’. If you want to get the display name ‘ Quick Campaign’ you should use the metadata service to fetch this detail. I don’t know of any other way to fetch this information. I just wanted to post this to help people save time and not waste energy on any other way. It is really easy to use Metadata service and retrieve this information.

Update Opportunities based on Exchange Rate

I have seen a couple of blogs where one can fetch the latest exchange rates from a service hosted on internet and then update the currency entity. However I have not seen any on what to do with latest exchange rate. I just wrote a workflow that runs in async mode and updates all foreign currency opportunities and related entities based on the latest exchange rates.

As part of this requirement users have the ability to start a dialog on the currency entity that in turn calls a custom workflow to update all open opportunities. As a result all the base currency fields are re-calculated to reflect the accurate base amount based on latest exchange rate. It is an asynchronous process as it can take hours to fetch all open opportunities, opportunity products and opportunity forecasts and update all of them based on latest exchange rates. It is envisaged that only System Administrators/trained users will initiate this process and that too only once in a year.

Architecture

The solution is implemented using a combination of dialog and child workflow. As a child workflow, a custom workflow registered using the plug-in registration tool is initiated that fetches and updates all open opportunities, opportunity forecasts and opportunity products in an asynchronous manner. The dialog is configured to run on the Currency View page in the ‘Business Management’ section of the application. One small little glitch in this solution is that in order to instantiate the dialog one has to select at least one currency in the View. This does not make sense as it gives the impression that the dialog / operation is going to be performed on the selected currency however as already stated the workflow is designed to update all open currency on latest exchange rate of all currencies and not just one currency.Here is the explanation of the problem

clip_image002

As one can see in the figure above that none of the entity is selected so the dialog cannot be launched. In order to launch the dialog one has to select the currency

clip_image004

This is where the user might feel that the dialog would run only for Australian dollar however the dialog runs for all the open opportunities irrespective of the currency. We have added error messages to somewhat reduce the impact but this problem remains.

clip_image006

 
Implemented Solution

Here is complete overview of the implemented solution:

Custom Workflow

1. ‘UpdateOpportunityExchangeRate’ class has the logic to fetch opportunities and related entities like opportunity forecasts and opportunity products.

2. By default the fetch query in CRM has a limit on the total number of records that can be fetched in a query. In order to by pass this one has to use ‘fetchXml’ and pass in the cookie to keep track of records fetched. This solution uses the same approach to fetch all the opportunities keeping track of the records being fetched.

3. An important aspect of the ‘money’ fields is that whenever a record is saved and one of the money fields is updated all the ‘money’ fields in the record are updated by CRM system. This is important to understand as this implies that all the ‘base_amounts’ are recalculated once a particular field is updated on a record.

4. Workflow uses the principle described in Step-3 to maximum as in-order to update all ‘money’ base value fields we just fetch and update one ‘money’ field. Doing this reduces the information flow to a great extent. This results in significant impact on the optimization of the overall code because this allows updating all ‘money’ fields without having to fetch and update each one of them.

Register workflow to CRM

1. Compile the solution to generate the assembly for the workflow.

2. Use the plug-in registration tool to register the plug-in to CRM. The plug-in registration tool is available as part of the SDK.

3. Once the assembly is registered in the CRM it is available to be used as the Child Workflow.

4. Child workflow always runs in the asynchronous mode.

Dialog

1. Out of the box dialog ‘Update all open opportunities with latest exchange rates’ is created in the CRM.

2. The dialog is configured on the Currency entity.

3. Dialog requires selection of at least one record for the execution of the dialog.

4. Dialogs ensure interaction with user to get approval to “update all open opportunities with all currencies”. This is required as confirmation must be obtained before all open opportunities are updated.

clip_image007

5. Once user approves the opportunity update process, workflow is instantiated in asynchronous mode.

6. Here is the detail of the workflow:

clip_image009

7. Workflow runs in the asynchronous mode in the background and performs the operations of updating the opportunities, opportunity forecasts and opportunity products.

Deployment

Here are the deployment steps for this solution:

Deployment using the Solution in CRM

1. As part of the deployment the following two artifacts must be added to the Solution that will imported to the desired organization:

a. Workflow:

i. “UpdateOpportunityExchRate.UpdateOpportunityExchangeRate”

b. Dialog:

i. “Update all open opportunities with latest exchange rates”

CRM 2011 Ribbon buttons

I recently implemented a functionality for one of our clients where they wanted help documents for each entity to be linked up to that entity. Help documents would reside in SharePoint and on ribbon button click the help document would open up. I documented that change and now I will just post the documentation here. I am sure it will help many interested in creating custom ribbons.

Help Documents – SharePoint

Custom Ribbons are created to link each entity with corresponding help document on the SharePoint site. Each entity that has a relevant help document available on SharePoint is linked via ribbon button. The purpose of the change is to allow users to get process related help on record creation for the entity that has help ribbon buttons.

Architecture

The overall architecture of this change is to link up each entity creation form in CRM with a custom page using ribbon button. This Custom page would open up the relevant help document on the SharePoint site based on entity on which the action was performed.

Implemented Solution

Here is the complete overview of the implemented solution:

Custom Ribbon

1. Generate ribbon Xml for all the ribbons in CRM using the sample provided in SDK. The location is provided in the document.

2. Ribbon Xml contains all the Groups for different entities. Each tab has all the groups and Scaling and Maxsize value of each group.

3. Under the tab identify the group where you want to add another group as shown in the figure below:

clip_image002[6]

4. Based on the structure in the generated ribbon Xml it is easy to create custom ribbon with the location and name. As part of this change we will create the group called “Help Group”.

5. Groups are added under the “CommandUIDefinition” section where the look and feel of Group and buttons inside the group is defined.

<RibbonDiffXml>

<CustomActions>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.CustomAction"

Location="Mscrm.Form.account.MainTab.Groups._children"

Sequence="110">

<CommandUIDefinition>

<Group Id="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Command="Mscrm.Form.account.MainTab.CustomGroup.Command"

Sequence="51"

Title="Help Group"

Description="$Resources(EntityDisplayName):Help document link"

Template="Mscrm.Templates.Flexible2">

6. The ‘Sequence’ in the Group tag defines where the group will appear on the CRM Entity Form.

7. Once we have added the Group then we add the buttons:

<Group Id="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Command="Mscrm.Form.account.MainTab.CustomGroup.Command"

Sequence="51"

Title="Help Group"

Description="$Resources(EntityDisplayName):Help document link"

Template="Mscrm.Templates.Flexible2">

<Controls Id="Mscrm.Form.account.MainTab.CustomGroup.Controls">

<Button Id="Mscrm.Form.account.MainTab.CustomGroup.HelpButton"

Command="Mscrm.Form.account.MainTab.CustomGroup.HelpButton.Command"

Sequence="10"

LabelText="Xxx Help"

Image16by16="$webresource:xxx_HelpIcon16x16"

Image32by32="$webresource:xxx_HelpIcon32x32"

ToolTipTitle="Help document for users"

ToolTipDescription="This button opens up the help document."

TemplateAlias="o1" />

</Controls>

</Group>

8. Under the button we define the Command that executes once the button is clicked. The action that is performed on the button Click is then defined in the ‘CommandDefinition’ section.

<CommandDefinitions>

<CommandDefinition Id="Mscrm.Form.account.MainTab.CustomGroup.HelpButton.Command">

<EnableRules/>

<DisplayRules/>

<Actions>

<Url Address="$webresource:xxx_OpenXxxHelpEntityDocument" PassParams="true"/>

</Actions>

</CommandDefinition>

<CommandDefinition Id="Mscrm.Form.account.MainTab.CustomGroup.Command">

<EnableRules>

<EnableRule Id="Mscrm.Enabled"/>

</EnableRules>

<DisplayRules/>

<Actions/>

</CommandDefinition>

9. Similarly under the “Custom Actions” section we define other ‘CustomAction’ for MaxSize and Scaling.

<CustomActions>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.MaxSize.CustomAction"

Location="Mscrm.Form.account.MainTab.Scaling._children"

Sequence="120">

<CommandUIDefinition>

<MaxSize Id="Mscrm.Form.account.MainTab.CustomGroup.MaxSize"

GroupId="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Sequence="21"

Size="LargeLarge" />

</CommandUIDefinition>

</CustomAction>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.Popup.CustomAction"

Location="Mscrm.Form.account.MainTab.Scaling._children"

Sequence="140">

<CommandUIDefinition>

<Scale Id="Mscrm.Form.account.MainTab.CustomGroup.Popup"

GroupId="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Sequence="85"

Size="Popup" />

</CommandUIDefinition>

</CustomAction>

</CustomActions>

10. Once we have created the Custom Ribbon we will add the ‘RibbonDiffXml’ to Customizations exported from CRM.

Adding Custom Ribbon to Solution

1. In order to add Custom Ribbon created above to the entity we need to first of all create a Solution in CRM and add the desired entity to that solution.

2. Export that solution and open up the ‘Customization.xml’ file.

3. Each entity that supports Custom Ribbons would contain the ‘RibbonDiffXml’ tag that needs to be replaced with the Custom Ribbon that we created.

clip_image004[6]

4. Once we have added our ‘Custom Ribbon’ to the FormXml we can zip the Customizations.xml to make it part of the Solution and on importing that solution in CRM our changes will start appearing on the entity for which we have added the Custom Ribbon.

5. Here is the complete Ribbon Xml for ‘Account Entity’

<RibbonDiffXml>

<CustomActions>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.CustomAction"

Location="Mscrm.Form.account.MainTab.Groups._children"

Sequence="110">

<CommandUIDefinition>

<Group Id="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Command="Mscrm.Form.account.MainTab.CustomGroup.Command"

Sequence="51"

Title="Help Group"

Description="$Resources(EntityDisplayName):Help document link"

Template="Mscrm.Templates.Flexible2">

<Controls Id="Mscrm.Form.account.MainTab.CustomGroup.Controls">

<Button Id="Mscrm.Form.account.MainTab.CustomGroup.HelpButton"

Command="Mscrm.Form.account.MainTab.CustomGroup.HelpButton.Command"

Sequence="10"

LabelText="Xxx Help"

Image16by16="$webresource:xxx_HelpIcon16x16"

Image32by32="$webresource:xxx_HelpIcon32x32"

ToolTipTitle="Help document for users"

ToolTipDescription="This button opens up the help document."

TemplateAlias="o1" />

</Controls>

</Group>

</CommandUIDefinition>

</CustomAction>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.MaxSize.CustomAction"

Location="Mscrm.Form.account.MainTab.Scaling._children"

Sequence="120">

<CommandUIDefinition>

<MaxSize Id="Mscrm.Form.account.MainTab.CustomGroup.MaxSize"

GroupId="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Sequence="21"

Size="LargeLarge" />

</CommandUIDefinition>

</CustomAction>

<CustomAction Id="Mscrm.Form.account.MainTab.CustomGroup.Popup.CustomAction"

Location="Mscrm.Form.account.MainTab.Scaling._children"

Sequence="140">

<CommandUIDefinition>

<Scale Id="Mscrm.Form.account.MainTab.CustomGroup.Popup"

GroupId="Mscrm.Form.account.MainTab.CustomGroup.CustomHelpGroup"

Sequence="85"

Size="Popup" />

</CommandUIDefinition>

</CustomAction>

</CustomActions>

<Templates>

<RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>

</Templates>

<CommandDefinitions>

<CommandDefinition Id="Mscrm.Form.account.MainTab.CustomGroup.HelpButton.Command">

<EnableRules/>

<DisplayRules/>

<Actions>

<Url Address="$webresource:xxx_OpenXxxHelpEntityDocument" PassParams="true"/>

</Actions>

</CommandDefinition>

<CommandDefinition Id="Mscrm.Form.account.MainTab.CustomGroup.Command">

<EnableRules>

<EnableRule Id="Mscrm.Enabled"/>

</EnableRules>

<DisplayRules/>

<Actions/>

</CommandDefinition>

</CommandDefinitions>

<RuleDefinitions>

<TabDisplayRules />

<DisplayRules />

<EnableRules />

</RuleDefinitions>

<LocLabels />

</RibbonDiffXml>

Custom Ribbon Action

1. Now that we have the ribbon in place we need to define what action we want to perform on button click.

2. In the Custom Ribbon we have following actions defined

<Actions>

<Url Address="$webresource:xxx_OpenXxxHelpEntityDocument" PassParams="true"/>

</Actions>

3. This means that on button Click “xxx_OpenXxxHelpEntityDocument” resource will be instantiated and it will be passed the default parameters like ‘entitytypecode’.

4. We will add our custom ‘html’ page as a resource so that our page is launched on the button click.

5. The functionality to open up the Xxx Help Document is part of the Html Page.

Custom Page Opening Help Documents

1. Custom Html Page uses following scripts:

a. JSON

b. Rest library

c. MetaData

2. Custom Page receives the entitytypecode from the Custom Ribbon button and based on that it generates the documents name.

3. Custom page creates the URL for the document by fetching Absolute site URL of the SharePoint site from the ‘SharePointSite’ record. Name of the site containing the Absolute Url has to be ‘Default Site Collection’.

4. Custom Page appends the Relative Url of the SharePoint site by fetching it from the ‘SharePointSite’. This Relative Url is picked from the site that is tagged as ‘Default’ site.

5. In addition Custom Page appends the SharePoint library ‘Relative Url’ by fetching it from the ‘SharePointDocumentLocation’. The name of the record containing this Relative Url has to be ‘CRM_HELP_Docs’.

6. Custom page appends the name of the document after fetching the display name using the ‘Metadata’ library based on the ‘entitytypecode’ received in the parameters sent by Custom Ribbon. The name of the document has the convention "Xxx_Help_EntiydisplayName".

7. In case any one of these sites or library locations are missing Custom Page will throw an exception.

Error Handling

1. In case of any exception the window opened on Ribbon button click closes and the error message is displayed to the users

Deployment

Here are the deployment steps for this solution

Deployment using the Solution added to Project

1. Project already contains the solution for the entities that are part of the initial scope. In order to deploy this solution just import ‘XxxCustomHelpRibbon_1_0_0_0.zip’ file in the organization.

2. This is the unmanaged solution so in order to deploy on machines where the roll back is desired please do not use this method to deploy the solution.

Deploying using the Solution in CRM

1. XxxDev contain the ‘XxxCustomHelpRibbon’ solution. In order to deploy this solution on other environments just export this solution in ‘managed solution’ mode and import that solution in the desired environment.