tag:blogger.com,1999:blog-50702964644713861882024-03-06T10:35:13.127+11:00Dynamics CRM Dev Down UnderMostly about my development experience with Dynamics CRM, C# and Javascript.RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.comBlogger42125tag:blogger.com,1999:blog-5070296464471386188.post-22337616627955591642020-05-28T19:58:00.000+10:002015-05-28T20:01:55.084+10:00Time to move on<div dir="ltr" style="text-align: left;" trbidi="on">
I impulse purchased a new domain. After experiencing a painful migration from blogger to wordpress, and further manual modifications, I present to you:<br />
<br />
<h2 style="text-align: center;">
<a href="http://dreamingincrm.com/" target="_blank">http://dreamingincrm.com/</a></h2>
<h2 style="text-align: left;">
</h2>
<div style="text-align: left;">
<br />
Please update your feed urls. I look forward to continuing my CRM experiments, in this new domain.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Thank you.</div>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-59060645727290356772015-05-25T21:45:00.004+10:002015-05-26T08:14:41.687+10:00Leverage Actions to bundle and minify form scripts<div dir="ltr" style="text-align: left;" trbidi="on">
<u><b>EDIT (26/05/15)</b></u>: I forgot to disable the plugin on RetrieveMultiple of webresource, described in the previous post. I also forgot to minify the script that runs on Form Experiment entity. Strangely however, this has reduced the performance. I tested this in CRMOnline, and so I am not sure if this is due to the load on the server at this time of the day. I have modified the performance screenshot, to reflect this.<br />
<br />
I tried another approach to dynamically minify and load CRM form script. This time I am utilising Actions. I have tried different ideas with Actions in the past and love how extensible and powerful they are. Of all the approaches I have tried so far, I like this a lot. As usual, if you would rather read code, head to <a href="https://github.com/rajyraman/DynamicScriptBundling">https://github.com/rajyraman/DynamicScriptBundling</a> and fork the code.<br />
<br />
This is the basic flow of this design:<br />
<ol style="text-align: left;">
<li>Form script just has code to invoke the action using current entityname as input parameter</li>
<li>Action uses the Form Load Sequence entity to collate a list of scripts that have to be minified and concatenated. The minified and concatenated script is stored in the Action's output parameter</li>
<li>The calling form script, evals the returned minified and concatenated script</li>
</ol>
Before you get <strike>defensive </strike>aggressive about using evals, please read <a href="http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/">http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/</a>. IMHO, it is perfectly alright to use eval in this scenario. Here are the steps:<br />
<br />
<b>Create the Action</b> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX2JwdIZ9psf4AlQmry520DIgrc3mP83e8XDDOKCbFquJbthhYXRzU-G6F0rtUesMFCgrgCaukGzyP_LYySc1vygzhaYg5VvZV9c08TpEVjRzd17zIMH-SJIgu5JmmZkaqvBXjM7hdLqI/s1600/Action.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX2JwdIZ9psf4AlQmry520DIgrc3mP83e8XDDOKCbFquJbthhYXRzU-G6F0rtUesMFCgrgCaukGzyP_LYySc1vygzhaYg5VvZV9c08TpEVjRzd17zIMH-SJIgu5JmmZkaqvBXjM7hdLqI/s640/Action.png" width="640" /></a></div>
The action doesn't contain much config, other than the input parameter and output parameter. The maximum length of the string, if you set this from the UI is 255, however, if you use a plugin to do the same, there is no limit. We are going to use this behaviour, to set the minifiedscripts with the bundled/concatenated scripts.<br />
<br />
<b>Create the Plugin that is triggered by the Action</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6-aha7gOuSQodpTq8yuJ7QxobW_VqCiX_w9IowQDW-lIiPV7LBylnWY5taVR0XFqdNpppHP8_O6kQc-kBlwPFoitQrA9X6ou6MTVLmNbcqdUWupzrcIK5qgSd265yKb5v5SK5WK7h6eQ/s1600/Plugin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6-aha7gOuSQodpTq8yuJ7QxobW_VqCiX_w9IowQDW-lIiPV7LBylnWY5taVR0XFqdNpppHP8_O6kQc-kBlwPFoitQrA9X6ou6MTVLmNbcqdUWupzrcIK5qgSd265yKb5v5SK5WK7h6eQ/s640/Plugin.png" width="640" /></a></div>
The Action's input argument is passed on to the Plugin's InputParameter and this is how the plugin knows, which entity it is dealing with. It then proceeds to concatenate and minify the scripts.<br />
<br />
<b>Plugin Code</b>
<br />
<pre class="prettyprint">using System.Text;
using DouglasCrockford.JsMin;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Linq;
using System.Xml.Linq;
using Contract = System.Diagnostics.Contracts.Contract;
namespace RYR.Experiments.Plugins
{
public class PostGetScriptsForEntity : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
Contract.Assert(serviceProvider != null, "serviceProvider is null");
var pluginExecutionContext =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
Contract.Assert(tracingService != null, "TracingService is null");
try
{
var factory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var organizationService = factory.CreateOrganizationService(pluginExecutionContext.UserId);
var entityName = pluginExecutionContext.InputParameters["entityname"];
var scriptLoadOrderFetchXml = string.Format(@"
<fetch count='1' >
<entity name='ryr_formloadsequence' >
<attribute name='ryr_name' />
<attribute name='ryr_scripts' />
<filter>
<condition attribute='ryr_name' operator='eq' value='{0}' />
</filter>
</entity>
</fetch>", entityName);
var concatenatedScripts = new StringBuilder();
var loadSequenceResults =
organizationService.RetrieveMultiple(new FetchExpression(scriptLoadOrderFetchXml))
.Entities;
if (!loadSequenceResults.Any()) return;
var scriptsToMerge = loadSequenceResults[0].GetAttributeValue<string>("ryr_scripts").Split(',');
var webresourceFetchXml = string.Format(@"
<fetch>
<entity name='webresource' >
<attribute name='content' />
<attribute name='name' />
<filter>
<condition attribute='webresourcetype' operator='eq' value='3' />
<condition attribute='name' operator='in' >
{0}
</condition>
</filter>
</entity>
</fetch>", string.Join(string.Empty,
scriptsToMerge.Select(x => string.Format("<value>{0}</value>", x))));
var toBeMergedWebResources = organizationService.RetrieveMultiple(
new FetchExpression(webresourceFetchXml)).Entities;
if (!toBeMergedWebResources.Any()) return;
foreach (var s in scriptsToMerge)
{
var matchedWebresource = toBeMergedWebResources
.FirstOrDefault(x => x.GetAttributeValue<string>("name") == s);
if (matchedWebresource != null)
{
concatenatedScripts.AppendLine(Encoding.UTF8.GetString(Convert.FromBase64String(
matchedWebresource.GetAttributeValue<string>("content"))));
}
else
{
concatenatedScripts.AppendLine(
string.Format(
"Xrm.Page.ui.setFormNotification('Unable to load {0}', 'ERROR', '{1}');", s,
Guid.NewGuid()));
}
}
pluginExecutionContext.OutputParameters["minifiedscripts"] = new JsMinifier().Minify(concatenatedScripts.ToString());
}
catch (Exception e)
{
tracingService.Trace(e.StackTrace);
throw;
}
}
}
}
</pre>
<br />
<b>Use Sdk.Soap.js to generate Javascript code for Action</b><br />
<br />
Download <a href="https://code.msdn.microsoft.com/SdkSoapjs-Action-Message-971be943">Sdk.Soap.js</a> and run the Sdk.SoapActionMessageGenerator.exe executable. Once you choose the organisation details and enter the credentials, the Javascript code for each individual action will be generated.<br />
<br />
<b>Modify the generated code to auto-populate entity name</b> <br />
<br />
The code generated by the Sdk.SoapActionMessageGenerator is going to be used in the form. We want to simply add this script to any entity, without having to change a single line of code. However, the Action accepts an input parameter called entity, that will obviously be different from entity to entity. Hence we have to make a slight modification to ensure that entityname is set automatically using Client API.<br />
<br />
Change<br />
<br />
<pre class="prettyprint">(function() {
this.ryr_GetScriptsForEntityRequest = function (
entityname
)
{
///<summary>
///
///</summary>
///<param name="entityname" type="String" />
/// [Add Description]
///
if (!(this instanceof Sdk.ryr_GetScriptsForEntityRequest)) {
return new Sdk.ryr_GetScriptsForEntityRequest(entityname);
}
</pre>
<br />
to<br />
<br />
<pre class="prettyprint">function () {
this.ryr_GetScriptsForEntityRequest = function ()
{
var entityname = Xrm.Page.data.entity.getEntityName();
///<summary>
///
///</summary>
///<param name="entityname" type="String" />
/// [Add Description]
///
if (!(this instanceof Sdk.ryr_GetScriptsForEntityRequest)) {
return new Sdk.ryr_GetScriptsForEntityRequest(entityname);
}
</pre>
<br />
I also had problem with strict mode and so I removed it from both Sdk.Soap.js and Sdk.ryr_GetScriptsForEntity.vsdoc.js. Now we merge both these scripts into one and add that as a javascript webresource. This webresource is then added to the form.<br />
<br />
Here is the script coming through in the Action response, before getting evaled.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJPUTBt3Gw8gN-9l2cXq7eZqsZCC4xJBUfURq0zwDLrl0JnrNauPFI1wpca8tA2yo8-kq8K_000qW_KOqqrWE3o6a42_j02eUYXETUxsZxhFGrTac13yq5pfvai8gliJcLmLfco97c7w0/s1600/Response.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJPUTBt3Gw8gN-9l2cXq7eZqsZCC4xJBUfURq0zwDLrl0JnrNauPFI1wpca8tA2yo8-kq8K_000qW_KOqqrWE3o6a42_j02eUYXETUxsZxhFGrTac13yq5pfvai8gliJcLmLfco97c7w0/s640/Response.png" width="640" /></a></div>
<br />
<br />
<b>Performance</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwxyUjXI-v1yaU4lqpNTPBdonaqlgshmuyzL7Cf785lsilr1dbrsBIAC1C-Av1zYMC6Go4XL3T5U0u-fO_6_PAw3rB6lXPBAv_KlzDoORsROwDhyphenhyphenKgGpv5Co5KCvIvo1gDmlnxLZ901h8/s1600/Performance.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="85" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwxyUjXI-v1yaU4lqpNTPBdonaqlgshmuyzL7Cf785lsilr1dbrsBIAC1C-Av1zYMC6Go4XL3T5U0u-fO_6_PAw3rB6lXPBAv_KlzDoORsROwDhyphenhyphenKgGpv5Co5KCvIvo1gDmlnxLZ901h8/s640/Performance.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
291 ms (minified and added to the form)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
vs</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
440 ms (dynamically minified using Action)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hope this gives you an idea on how you can use Action to solve the script load sequence issue in CRM2015. </div>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-69080061823980647592015-05-23T20:25:00.000+10:002015-05-23T20:29:03.120+10:00Form Script Bundling and Minification<div dir="ltr" style="text-align: left;" trbidi="on">
Ever since form script loading was made async, I have tried different ways to ensure that form scripts will be loaded in the sequence I want, and not how CRM wants it to be, a.k.a random. CRM2015 Update 1 has introduced Turbo Forms. Turbo Forms are supposed to drastically improve form render time. The problem of managing script dependencies, is still left to the developer. You basically have two options: <br />
<ol style="text-align: left;">
<li>In build stage, bundle and minify the scripts in the order of dependencies and use this in the form.</li>
<li>Write self contained scripts, without any dependencies.</li>
</ol>
I tried out an approach using Plugin and couple of entities to try solve this. If you would rather read the code, you can download the source from <a href="https://github.com/rajyraman/DynamicScriptBundling" target="_blank">https://github.com/rajyraman/DynamicScriptBundling</a>. I have also included the managed and unmanaged solutions in the repo.<br />
<br />
<u><b>Components</b></u><br />
<br />
1. Form Load sequence entity, that stores the entity name and scripts that are to be loaded<br />
<i> </i>2. A blank javascript webresource, whose name is in this pattern: [<i>entityname</i>].crmform.min.js<i> </i><br />
<i> </i>3.<i> </i>A plugin the runs on post-RetrieveMultiple on webresource entity<br />
<br />
<u><b>How it is wired up</b></u><br />
<br />
[<i>entityname</i>].crmform.min.js is added to the form, that requires bunding and minification. This script just contains a comment, and nothing else.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEpJOyqRA3shPsop1lkgqWvGt4oE0mwKoo9Ueyv-PkKKmsK8JZGYBlqzkhyphenhypheniUnN6GsQ_loMqdjyfMhC7rL4x5Vy_u6Gt5C01iU1fbEaYF8vJ3OW6VnFQ9R9JDzySsPqFD-SbyYIBP7hb8/s1600/formwireup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEpJOyqRA3shPsop1lkgqWvGt4oE0mwKoo9Ueyv-PkKKmsK8JZGYBlqzkhyphenhypheniUnN6GsQ_loMqdjyfMhC7rL4x5Vy_u6Gt5C01iU1fbEaYF8vJ3OW6VnFQ9R9JDzySsPqFD-SbyYIBP7hb8/s640/formwireup.png" width="582" /></a></div>
<br />
Create a <i>Form Load Sequence</i> record, that specifies the entity name and the scripts that loaded be minified for this entity. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg07MfPemv1yFBlphOF3b83Kdr2vZ-ekbgwsTViph8E6c36Uijh2P-wHKguGj3kBsXxlxYizJ0YS-pXD6IA0pu3R3PlijRSqewVrUPgvaIc5Bp1pyY0f1VZm9NfwX89GpwAlj84H8dMXqw/s1600/formloadsequence.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg07MfPemv1yFBlphOF3b83Kdr2vZ-ekbgwsTViph8E6c36Uijh2P-wHKguGj3kBsXxlxYizJ0YS-pXD6IA0pu3R3PlijRSqewVrUPgvaIc5Bp1pyY0f1VZm9NfwX89GpwAlj84H8dMXqw/s640/formloadsequence.png" width="640" /></a></div>
<br />
Register the plugin on post <i>RetrieveMultiple </i>of <i>webresource </i>entity.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhjtWk9YmLcoLiOky32c0s8s967qNezNLIoZqu5yBD5mxv_MeTFgHsNlvPP_m357BUlgmSiP7VoqEn8dfLEooub-Ajy2Vu4m9sTXms5FgvNRQQ8fahUqqtLbnNoOPYsi8MkfGiT3D95HE/s1600/PluginStep.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="616" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhjtWk9YmLcoLiOky32c0s8s967qNezNLIoZqu5yBD5mxv_MeTFgHsNlvPP_m357BUlgmSiP7VoqEn8dfLEooub-Ajy2Vu4m9sTXms5FgvNRQQ8fahUqqtLbnNoOPYsi8MkfGiT3D95HE/s640/PluginStep.png" width="640" /></a></div>
<u><b>How it works</b></u><br />
<br />
If you have read the plugin code already, you already know. But you haven't here is how it works:<br />
The plugin retrieves the Query key on the PluginExecutionContext's InputParameter that contains the QueryExpression object. It then checks, if there is a condition on this QueryExpression with name like crmform.min.js. If so, it retrieves the correct Form Load sequence record for the current entity.<br />
<br />
Using the script sequence specified, it also retrieves the script webresources, concatenates and minifies them. This concatenated script is then used to update the OutputParameter's BusinessEntityCollection. The plugin also checks if the javascript webresources specified in the form load sequence entity, actually exists. It displays an error, if it doesn't.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGnY_fuj0e_2kYS9xEWT3C9_7eS1t3kSx6ncVCdfWLOtky2ywQqjlu6oQMLUobQbajme4IuwHExt94VrPLQtISOHYqCNHLEoOjYv4G6AzCp0pOcBsmswV2ERP3Aw7CgKVfRwLVfmeFyx4/s1600/FormExperiment.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGnY_fuj0e_2kYS9xEWT3C9_7eS1t3kSx6ncVCdfWLOtky2ywQqjlu6oQMLUobQbajme4IuwHExt94VrPLQtISOHYqCNHLEoOjYv4G6AzCp0pOcBsmswV2ERP3Aw7CgKVfRwLVfmeFyx4/s1600/FormExperiment.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUP5nwh_GYkl1YWmcuKEW9VA0u_6BPHz4DKTWOwcJSLl27vy9QgQ5376I1ZDyhiM2_s36IKH2ycIyWTN92lzk57wYI8j03H-SFf_h76i1uzoptHZwCT-E4gjdtQW2WEMB5C_0CZpytRMg/s1600/FormExperiment.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
<br />
<u><b>ExecutionContext for RetrieveMultiple on webresource - Post Stage</b></u><br />
<br />
<pre class="prettyprint"><Profile>
<Configuration i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ConstructorDurationInMilliseconds>2</ConstructorDurationInMilliseconds>
<ConstructorException i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ConstructorStartTime>2015-05-22T14:04:15.5180427Z</ConstructorStartTime>
<Context>
<z:anyType i:type="PluginExecutionContext" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BusinessUnitId>bf0d0d94-ddc9-e411-80db-c4346bad5414</BusinessUnitId>
<CorrelationId>b668ab80-1dda-4676-8615-8d82e9ea0ff0</CorrelationId>
<Depth>1</Depth>
<InitiatingUserId>80151b28-fb9a-4d38-a920-d8f4d33ffcc2</InitiatingUserId>
<InputParameters xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<a:KeyValuePairOfstringanyType>
<b:key>Query</b:key>
<b:value i:type="a:QueryExpression">
<a:ColumnSet>
<a:AllColumns>false</a:AllColumns>
<a:Columns xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<c:string>webresourceid</c:string>
<c:string>name</c:string>
<c:string>content</c:string>
<c:string>webresourcetype</c:string>
<c:string>silverlightversion</c:string>
</a:Columns>
</a:ColumnSet>
<a:Criteria>
<a:Conditions>
<a:ConditionExpression>
<a:AttributeName>name</a:AttributeName>
<a:Operator>Equal</a:Operator>
<a:Values xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<c:anyType i:type="d:string" xmlns:d="http://www.w3.org/2001/XMLSchema">ryr_formexperiment.crmform.min.js</c:anyType>
</a:Values>
<a:EntityName i:nil="true" />
</a:ConditionExpression>
</a:Conditions>
<a:FilterOperator>And</a:FilterOperator>
<a:Filters />
</a:Criteria>
<a:Distinct>false</a:Distinct>
<a:EntityName>webresource</a:EntityName>
<a:LinkEntities />
<a:Orders />
<a:PageInfo>
<a:Count>0</a:Count>
<a:PageNumber>0</a:PageNumber>
<a:PagingCookie i:nil="true" />
<a:ReturnTotalRecordCount>false</a:ReturnTotalRecordCount>
</a:PageInfo>
<a:NoLock>false</a:NoLock>
</b:value>
</a:KeyValuePairOfstringanyType>
</InputParameters>
<IsExecutingOffline>false</IsExecutingOffline>
<IsInTransaction>false</IsInTransaction>
<IsOfflinePlayback>false</IsOfflinePlayback>
<IsolationMode>2</IsolationMode>
<MessageName>RetrieveMultiple</MessageName>
<Mode>0</Mode>
<OperationCreatedOn>2015-05-22T14:04:15.0754261Z</OperationCreatedOn>
<OperationId>00000000-0000-0000-0000-000000000000</OperationId>
<OrganizationId>32d64867-9081-49c2-8196-6304db7d47e1</OrganizationId>
<OrganizationName>Contoso</OrganizationName>
<OutputParameters xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<a:KeyValuePairOfstringanyType>
<b:key>BusinessEntityCollection</b:key>
<b:value i:type="a:EntityCollection">
<a:Entities>
<a:Entity>
<a:Attributes>
<a:KeyValuePairOfstringanyType>
<b:key>webresourceid</b:key>
<b:value i:type="z:guid">02fe0b47-8800-e511-80ef-c4346bada558</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>name</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">ryr_formexperiment.crmform.min.js</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>content</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">Ly9yeXJfZm9ybWV4cGVyaW1lbnQuY3JtZm9ybS5taW4uanM=</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>webresourcetype</b:key>
<b:value i:type="a:OptionSetValue">
<a:Value>3</a:Value>
</b:value>
</a:KeyValuePairOfstringanyType>
</a:Attributes>
<a:EntityState i:nil="true" />
<a:FormattedValues>
<a:KeyValuePairOfstringstring>
<b:key>webresourcetype</b:key>
<b:value>Script (JScript)</b:value>
</a:KeyValuePairOfstringstring>
</a:FormattedValues>
<a:Id>02fe0b47-8800-e511-80ef-c4346bada558</a:Id>
<a:KeyAttributes xmlns:c="http://schemas.microsoft.com/xrm/7.1/Contracts" />
<a:LogicalName>webresource</a:LogicalName>
<a:RelatedEntities />
<a:RowVersion>1308124</a:RowVersion>
</a:Entity>
</a:Entities>
<a:EntityName>webresource</a:EntityName>
<a:MinActiveRowVersion>-1</a:MinActiveRowVersion>
<a:MoreRecords>false</a:MoreRecords>
<a:PagingCookie><cookie page="1"><webresourceid last="{02FE0B47-8800-E511-80EF-C4346BADA558}" first="{02FE0B47-8800-E511-80EF-C4346BADA558}" /></cookie></a:PagingCookie>
<a:TotalRecordCount>-1</a:TotalRecordCount>
<a:TotalRecordCountLimitExceeded>false</a:TotalRecordCountLimitExceeded>
</b:value>
</a:KeyValuePairOfstringanyType>
</OutputParameters>
<OwningExtension xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
<a:Id>34846b5c-8b00-e511-8101-c4346bade5b0</a:Id>
<a:KeyAttributes xmlns:b="http://schemas.microsoft.com/xrm/7.1/Contracts" xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<a:LogicalName>sdkmessageprocessingstep</a:LogicalName>
<a:Name>RYR.Experiments.PreRetrieveMultipleWebResource: RetrieveMultiple of webresource (Profiler)</a:Name>
<a:RowVersion i:nil="true" />
</OwningExtension>
<PostEntityImages xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<PreEntityImages xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<PrimaryEntityId>00000000-0000-0000-0000-000000000000</PrimaryEntityId>
<PrimaryEntityName>webresource</PrimaryEntityName>
<RequestId i:nil="true" />
<SecondaryEntityName>none</SecondaryEntityName>
<SharedVariables xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<UserId>80151b28-fb9a-4d38-a920-d8f4d33ffcc2</UserId>
<ParentContext i:nil="true" />
<Stage>40</Stage>
</z:anyType>
</Context>
<ExecutionDurationInMilliseconds>14</ExecutionDurationInMilliseconds>
<ExecutionException i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ExecutionStartTime>2015-05-22T14:04:15.5180427Z</ExecutionStartTime>
<HasServiceEndpointNotificationService>true</HasServiceEndpointNotificationService>
<IsContextReplay>false</IsContextReplay>
<IsolationMode>2</IsolationMode>
<OperationType>Plugin</OperationType>
<ProfileVersion>1.1</ProfileVersion>
<ReplayEvents xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<SecureConfiguration i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<TypeName>RYR.Experiments.PreRetrieveMultipleWebResource</TypeName>
<WorkflowInputParameters xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<WorkflowOutputParameters xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<WorkflowStepId i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
</Profile>
</pre>
<br />
<b>Performance</b><br />
There is a bit of overhead, as the plugin has to retrieve and minify the webresources.<br />
<br />
<b> </b><br />
<u><i>Scripts minified at build stage and added to the form</i></u><br />
<br />
<b></b>
It takes 291ms.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxByaE-hGQrVUgOA-Ev95Ls8IZlb-FnkFS79_ONU2UWMIOJvQXFNtrEQMOPwepKI3Ksil5j2nAxe6rnu0SUsszng_s7Y3hGCV6i-TCJVOc3kZf6JsiPlEWfpaF54fVNWg7N7KVPoQQ-jk/s1600/WithoutDynamicBundlingAndMinification.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxByaE-hGQrVUgOA-Ev95Ls8IZlb-FnkFS79_ONU2UWMIOJvQXFNtrEQMOPwepKI3Ksil5j2nAxe6rnu0SUsszng_s7Y3hGCV6i-TCJVOc3kZf6JsiPlEWfpaF54fVNWg7N7KVPoQQ-jk/s1600/WithoutDynamicBundlingAndMinification.png" /></a></div>
<br />
<u><i>Script dynamically bundled and minified by plugin</i></u><br />
<br />
It takes 481ms.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3JlOYtsQsJbV1IcP_lT4rbOpHC18dtUAYjbWYj981wWcStcHHteWnB01O7GBjaL6fhhNQcPFHWGUYMUFhy4Qg6Kpra-UwH80u0HIPHoPNqfz6RXe8RdMkQjhXehmPDdUnbFUnfkeZm-w/s1600/WithDynamicBundlingAndMinification.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3JlOYtsQsJbV1IcP_lT4rbOpHC18dtUAYjbWYj981wWcStcHHteWnB01O7GBjaL6fhhNQcPFHWGUYMUFhy4Qg6Kpra-UwH80u0HIPHoPNqfz6RXe8RdMkQjhXehmPDdUnbFUnfkeZm-w/s1600/WithDynamicBundlingAndMinification.png" /></a></div>
<br />
Take this numbers, with a pinch of salt, as I found the performance can vary quite a bit depending on the time of the day, as I tested this in CRMOnline. I also tested this with cache disabled.<br />
<br />
<b><u>Failures along the way</u></b><br />
I tried these approaches which, didn't quite workout, but I want to document them for future reference.<br />
<ol style="text-align: left;">
<li>Adding a non-existent form script into the<i> Form Experiment</i>'s FormXml doesn't work, even though there is plugin to take care of the <i>RetrieveMultiple </i>request. CRM doesn't allow this to happen. The Javascript webresource has to exist, if you want to add this to a form. Here is what you'll have to add to the root node of the formxml, to hook up the webresource and associated onsave and onload event handlers for the form<br /><br />
<pre class="prettyprint"><formLibraries>
<Library name='[JSWEBRESNAME]' libraryUniqueId='[NEWGUID]' />
</formLibraries>
<events>
<event name='onload' application='false' active='false'>
<Handlers>
<Handler functionName='[FUNCNAME]' libraryName='[JSWEBRESNAME]' handlerUniqueId='[NEWGUID]' enabled='true' parameters='' passExecutionContext='false' />
</Handlers>
</event>
<event name='onsave' application='false' active='false'>
<Handlers>
<Handler functionName='[FUNCNAME]' libraryName='[JSWEBRESNAME]' handlerUniqueId='[NEWGUID]' enabled='true' parameters='' passExecutionContext='false' />
</Handlers>
</event>
</events>
</pre>
<br />
</li>
<li>I tried to use <a href="https://github.com/PureKrome/YUICompressor.NET" target="_blank">YUICompressor.NET</a>, but it is not strongly signed and had a dependency on Ecmascript.net, which is also not strongly signed. It seems too much pain to sign these third party assemblies and merge this with my plugin. If you love pain, have a look at <a href="http://buffered.io/posts/net-fu-signing-an-unsigned-assembly-without-delay-signing/" target="_blank">http://buffered.io/posts/net-fu-signing-an-unsigned-assembly-without-delay-signing/</a> on how this can be done. I ended up using <a href="https://github.com/Taritsyn/JSMin.NET" target="_blank">JSMin.net</a> as it is just two files in total, and you can just add this to you project and build, instead of merging third-party assemblies.</li>
</ol>
<u><b>My previous posts on the same subject</b></u><br />
<ol style="text-align: left;">
<li><a href="http://nycrmdev.blogspot.com.au/2015/01/an-alternative-approach-to-loading-form.html" target="_blank">http://nycrmdev.blogspot.com.au/2015/01/an-alternative-approach-to-loading-form.html</a></li>
<li><a href="http://nycrmdev.blogspot.com.au/2014/04/using-requirejs-in-crm2013.html">http://nycrmdev.blogspot.com.au/2014/04/using-requirejs-in-crm2013.html</a></li>
</ol>
<u><b>References</b></u> <br />
<br />
<ol style="text-align: left;">
<li><a href="https://www.develop1.net/public/post/Ghost-Web-Resources-Client-Metadata-Caching.aspx" target="_blank">Scott Durow - Ghost Webresources</a> </li>
<li><a href="https://crmbusiness.wordpress.com/2015/05/20/crm-2015-sp1-turbo-forms-use-asynchronous-javascript-web-resource-loading/" target="_blank">Ben Hosk - Turbo Forms</a> </li>
<li><a href="https://msdn.microsoft.com/en-us/library/gg328261%28v=crm.7%29.aspx" target="_blank">MSDN - Write Code for CRM Forms</a> </li>
</ol>
<ol style="text-align: left;">
</ol>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-23811621872109135972015-05-22T10:10:00.003+10:002015-05-22T11:14:32.136+10:00Redux: RetrieveMultiple on large datasets<div dir="ltr" style="text-align: left;" trbidi="on">
In trying to optimise, <i>RetrieveMultiple</i> performance I thought I had hit a sweet-spot with using TPL, with <i>RetrieveMultiple </i>request spanning across pages, but after talking to @maustinjones, I now have come to the conclusion, that is probably not the best approach. The dataset size I tested on: contact and account, are large, but not significantly large. After looking at the SQL Trace logs, I have decided to stick with the pagingcookie approach, while dealing with large datasets.<br />
<br />
In order to understand, why the pagingcookie approach is more efficient, it is important to understand, how your FetchXml is translated into SQL.<br />
<br />
<u><b>Scenario</b></u>:<br />
Retrieve all records from account. Total Number of records is 10,177<br />
<br />
<u><b>Approach 1 - TPL with RetrieveMultiple parallised across pages</b></u><br />
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoNormalTable" style="background: #DEEAF6; mso-background-themecolor: accent1; mso-background-themetint: 51; mso-cellspacing: 0cm; mso-padding-alt: 0cm 0cm 0cm 0cm; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">Request</span></b></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">FetchXml</span></b></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">Translated SQL</span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">1</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="1"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 5001 "account0".Name as "name",
"account0".AccountId as "accountid" </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">from AccountBase as
"account0" WITH (NOLOCK) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">where
(("account0".StateCode = @StateCode0)) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">order by
"account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">2</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="2"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 10001 "account0".Name as "name",
"account0".AccountId as "accountid" </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">from AccountBase as
"account0" WITH (NOLOCK) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">where
(("account0".StateCode = @StateCode0)) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">order by
"account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">3</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="3"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 15001 "account0".Name as "name",
"account0".AccountId as "accountid" </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">from AccountBase as
"account0" WITH (NOLOCK) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">where
(("account0".StateCode = @StateCode0)) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">order by
"account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 4;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">4</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="4"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 20001 "account0".Name as "name",
"account0".AccountId as "accountid" </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">from AccountBase as
"account0" WITH (NOLOCK) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">where
(("account0".StateCode = @StateCode0)) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">order by
"account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 5; mso-yfti-lastrow: yes;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">5</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 338.45pt;" valign="top" width="451"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="5"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 318.9pt;" valign="top" width="425"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 25001 "account0".Name as "name",
"account0".AccountId as "accountid" </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">from AccountBase as
"account0" WITH (NOLOCK) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">where
(("account0".StateCode = @StateCode0)) </span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">order by
"account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
</tbody></table>
<br />
<br />
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]-->As you can see, the SQL query that is generated, is not exactly optimal. There are only 10,177 records in total, but 45,533 records (5001 + 10001 + 10177 + 10177 + 10177) are retrieved across 5 requests. The correct number of records (10,177) are returned only after further in-memory processing.<br />
<br />
<u><b>Approach 2 - PagingCookie</b></u><br />
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoNormalTable" style="background: #DEEAF6; mso-background-themecolor: accent1; mso-background-themetint: 51; mso-cellspacing: 0cm; mso-padding-alt: 0cm 0cm 0cm 0cm; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">Request</span></b></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 204.0pt;" valign="top" width="272"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">FetchXml</span></b></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 149.8pt;" valign="top" width="200"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">Paging Cookie</span></b></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 307.8pt;" valign="top" width="410"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<b><span style="color: black; mso-themecolor: text1;">Translated SQL</span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">1</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 204.0pt;" valign="top" width="272"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="1"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 149.8pt;" valign="top" width="200"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">NULL</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 307.8pt;" valign="top" width="410"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 5001 "account0".Name as "name",
"account0".AccountId as "accountid" from AccountBase as
"account0" where (("account0".StateCode = @StateCode0))
order by "account0".AccountId asc',N'@StateCode0 int',@StateCode0=0</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">2</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 204.0pt;" valign="top" width="272"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="2"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 149.8pt;" valign="top" width="200"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><cookie page="1"><accountid
first="{4005F675-164D-E411-80D3-00155D018813}" last="{71C7E14D-357C-E411-80D8-00155D018813}"/></cookie></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 307.8pt;" valign="top" width="410"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 5001 "account0".Name as "name",
"account0".AccountId as "accountid" from AccountBase as
"account0" where (("account0".StateCode = @StateCode0)
and (("account0".AccountId > @AccountId0))) order by
"account0".AccountId asc',N'@StateCode0 int,@AccountId0
uniqueidentifier',@StateCode0=0,@AccountId0='71C7E14D-357C-E411-80D8-00155D018813'</span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3; mso-yfti-lastrow: yes;">
<td style="padding: 0cm 0cm 0cm 0cm; width: 51.0pt;" valign="top" width="68"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">3</span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 204.0pt;" valign="top" width="272"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><fetch page="3"
no-lock="true" count="5000"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><entity name="account"></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><attribute name="name"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><order attribute="accountid"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><condition attribute="statecode"
value="0" operator="eq"/></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></filter></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></entity></span></div>
<div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"></fetch></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 149.8pt;" valign="top" width="200"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;"><cookie page="2"><accountid
first="{77C7E14D-357C-E411-80D8-00155D018813}" last="{968467AD-357C-E411-80D8-00155D018813}"/></cookie></span></div>
</td>
<td style="padding: 0cm 0cm 0cm 0cm; width: 307.8pt;" valign="top" width="410"><div class="MsoNormal" style="line-height: normal; margin-bottom: .0001pt; margin-bottom: 0cm;">
<span style="color: black; mso-themecolor: text1;">exec sp_executesql N'select
top 5001 "account0".Name as "name",
"account0".AccountId as "accountid" from AccountBase as
"account0" where (("account0".StateCode = @StateCode0)
and (("account0".AccountId > @AccountId0))) order by
"account0".AccountId asc',N'@StateCode0 int,@AccountId0
uniqueidentifier',@StateCode0=0,@AccountId0='968467AD-357C-E411-80D8-00155D018813'</span></div>
</td>
</tr>
</tbody></table>
<br />
10,179 records (5001+5001+177) are retrieved across three requests, and further processing cuts down the result record set to the correct count of 10,177.<br />
<br />
<u><b>Random Notes:</b></u><br />
Looking at how paging cookie translated to SQL, reminds me of this post from PFE Dynamics guys -> <a href="http://blogs.msdn.com/b/crminthefield/archive/2015/01/19/the-dangers-of-guid-newguid.aspx" target="_blank">Dangers of Guid.NewGuid</a>. I believe that the entity primary key is generated using <a href="https://msdn.microsoft.com/en-us/library/ms189786.aspx" target="_blank">NEWSEQUENTIALID</a>, and hence it is not advisable to insert records directly into the MSCRM database. This is also probably how "> uniqueidentifier" query is optimised, as the Guid is in sequence, and the clustered index on the primary key can be efficiently used in this query.<br />
<br />
<u><b></b></u> <br />
<u><b>Conclusion</b></u>: <br />
So, compared to the TPL approach, paging cookie approach<br />
<ol style="text-align: left;">
<li>Reduces the number of queries sent to the database</li>
<li>Respects the count size specified in the fetchxml</li>
<li>Does less in-memory processing </li>
<li>Reduces the chances of encountering a database lock</li>
</ol>
<br />
In spite of all these obversations, and understanding how efficient the pagingcookie queries are, I still cannot comprehend how TPL is faster, even though it inefficiently queries the database. <br />
<br />
<u><b>Credit</b></u>: Big thank you to @maustinjones in helping me understand the performance pitfills when using TPL, in this scenario.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-87520458652543998912015-05-21T11:47:00.002+10:002015-05-22T11:11:45.660+10:00RetrieveMultiple performance on large datasets<div dir="ltr" style="text-align: left;" trbidi="on">
<u><b>EDIT (21/05/15):</b></u> After DMing with <a href="https://twitter.com/maustinjones" target="_blank">@maustinjones</a>, I have added stat for paged <i>RetrieveMultiple </i>as well. I have updated the post to include this.<br />
<br />
<u><b>EDIT (22/05/15):</b></u> Updated post to reflect correct behaviour of no-lock when parallelising. Thanks @maustinjones. Please also refer to the follow up post -> <a href="http://nycrmdev.blogspot.com.au/2015/05/redux-retrievemultiple-with-large.html" target="_blank">http://nycrmdev.blogspot.com.au/2015/05/redux-retrievemultiple-with-large.html</a> on why paging cookie, is the recommended approach.<br />
<br />
MSCRM limits the maximum result size to 5000 records, when you use the <i>RetrieveMultiple </i>request. In order to overcome this and retrieve all the records, you'll have to use paging. PFEDynamics team have also released an open-source library called <a href="https://pfexrmcore.codeplex.com/" target="_blank">PFE Xrm Core Library</a> that utilises <a href="https://msdn.microsoft.com/en-us/library/dd460717%28v=vs.110%29.aspx" target="_blank">Task Parallel Library</a>.<br />
<br />
There is also <a href="https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.messages.executemultiplerequest.aspx" target="_blank"><i>ExecuteMultipleRequest</i></a> that you can use to send bunch of requests in one go, and process the responses. This just wanted to document by findings, about the performance of these options:<br />
<ol style="text-align: left;">
<li>Just using Parallel.ForEach</li>
<li>ExecuteMultipleRequest</li>
<li>PFE Xrm Core</li>
<li>Paged RetrieveMultiple </li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<u><b>Run 1</b></u> (Batch size 1000):<br />
I have not included the paged <i>RetrieveMultiple </i>in this scenario, as it is too slow, and I am too impatient to wait for it to complete. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgtexNv9Pu-shOeuafbwhI51747KpND7OAi2exeX1t_AIJbkFxya_QIZJjkk0mmg6zDie148K9J4oNco85W6Om6JB7BGeH5pk6kOx1OWLByvyrH8MdCnq6AmDFMiVfut9NpCfBqUL3QQk/s1600/PageSize1000.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="482" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgtexNv9Pu-shOeuafbwhI51747KpND7OAi2exeX1t_AIJbkFxya_QIZJjkk0mmg6zDie148K9J4oNco85W6Om6JB7BGeH5pk6kOx1OWLByvyrH8MdCnq6AmDFMiVfut9NpCfBqUL3QQk/s640/PageSize1000.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<u><b>Run 2</b></u> (Batch size 5000):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_LdYM2SFihLwR7JUF-fZqEQJ2ysloaYlS4cfnRfBZCLIhQjN4cScBQWyGDUW5R9M_fWJJnv7QreBbMXh404l0n1hFeioiO8x3S0gbzAQkzJWDi6fa87WI6H1j7q-wPeJXjcHdGZClkCk/s1600/PageSize5000-Run1-Attempt2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="504" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_LdYM2SFihLwR7JUF-fZqEQJ2ysloaYlS4cfnRfBZCLIhQjN4cScBQWyGDUW5R9M_fWJJnv7QreBbMXh404l0n1hFeioiO8x3S0gbzAQkzJWDi6fa87WI6H1j7q-wPeJXjcHdGZClkCk/s640/PageSize5000-Run1-Attempt2.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMEs3mDTfQnVS-6d5QmPmdfljcUfaXuEa1vq9mQNZhaDGuc2u7KeZ5R9rFIi5UAHLkdr7KIDrDmRsFITXshpNtTRvR_AQlv1Ouf3K8OOjVttp-zQ6C_egURafZtSOKNuouFEVWSs_YOuc/s1600/PageSize5000-Run1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
<u><b>Run 3</b></u> (Batch size 5000):<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSHiC1K7OiPKlQtwxkzXuvOzNooyFWsRnHmk7RqoBUMsuLJpb8m8qI0A5lOMxv_-rk33n_APrjDQeuyWCtyxGzuKgVa64gesJgaoEcDTMQvBSJDB-5J6sBgHl6mhgRs-6pGHXIpdAEK0Y/s1600/PageSize5000-Run2-Attempt2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="460" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSHiC1K7OiPKlQtwxkzXuvOzNooyFWsRnHmk7RqoBUMsuLJpb8m8qI0A5lOMxv_-rk33n_APrjDQeuyWCtyxGzuKgVa64gesJgaoEcDTMQvBSJDB-5J6sBgHl6mhgRs-6pGHXIpdAEK0Y/s640/PageSize5000-Run2-Attempt2.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_o_D_UBbblyq_zxb4BP9XfcWTIcoANK0EvdDJQvC58AhdnhAaquVpCzF7w4UMyUI5tfvufNXRQ1Ba2pPQ7A7aanhEU0ev0rrFrJjdFmMSJJiBmeUIK_XvabBUSLWQqpMoMvx6hS-Ben4/s1600/PageSize5000-Run2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
<b><u>Observations:</u></b><br />
<ol style="text-align: left;">
<li>Reducing the page size causes a drop in performance. I got better performance with 5000 records in one page, than 1000 records</li>
<li>Just using <i>Parallel.ForEach</i> is faster than PFE Xrm Core (some overhead in instantiating the service perhaps?)</li>
<li><i>ExecuteMultipleRequest </i>is significantly slower than <i>Parallel.ForEach</i></li>
</ol>
<u><b>Best Practice tip from PFE Dynamics</b></u>:<br />
<br />
If you read the source code for the <a href="https://pfexrmcore.codeplex.com/SourceControl/latest#v5/Client/ParallelServiceProxy.cs" target="_blank">ParallelServiceProxy</a> class, the help text for the <i>RetrieveMultiple</i> method actually has this note:<br />
<br />
<div style="background: #1C3006; border: 1px solid grey; padding: 5px;">
IMPORTANT!! This approach should only be used if multiple queries for varying entity types are required or the result set can't be expressed in a single query. In the latter case, <br />
leverage NoLock=true where possible to reduce database contention.
</div>
<br />
So ideally, you should be using <i>RetrieveMultiple </i>method in <i>ParallelProxy</i>, to retrieve records from multiple entities. But, in my case I am retrieving from the same entity, hence I am using the <i>no-lock </i>option the fetchxml.<br />
<br />
DMed with @maustinjones, and here is an important point to consider, before choosing a technique.<i> </i><br />
<br />
<u><b><i>Query pages shouldn't be retrieved in parallel. only separate queries altogether</i></b> </u><br />
<br />
<strike>When you use TPL to submit a bunch of <i>RetrieveMultiple </i>requests in one go, there is a chance of encountering database lock issues, even though you use <i>no-lock. </i>So, it is OK to parallelise queries that fetch from different entities, but using PagingCookie is the recommended approach.</strike><br />
<strike><br /></strike>
<strike>To be honest, I did not experience any lock issues during the test, but standard CRM load was not simulated during the test. I am not sure what would have happened, if users were viewing contacts/running reports on contacts, and I am running these tests at the same time.</strike><br />
Database contentention and locking is applicable only in scenarios, where no-lock is not feasible.<br />
<br />
TPL just blitzes the other techniques in these tests, but I'll have to test this further to see if lock contention issues arise, in much larger datasets. Do consider PFE Xrm Core, if you are looking to use RetrieveMultiple from multiple entities. It is written by the PFE Dynamics guys and is open-source.<br />
<br />
<u><b>Best Practice tips from msdn regarding TPL</b></u>:<br />
<br />
This article in msdn is a must read if you are thinking of using TPL -> <a href="https://msdn.microsoft.com/en-us/library/dd997392%28v=vs.110%29.aspx" target="_blank">https://msdn.microsoft.com/en-us/library/dd997392%28v=vs.110%29.aspx.</a><br />
<br />
I had performance issues with TPL, as I had <i>Console.WriteLine</i> inside the lambda for ForEach, and it basically killed the performance. The article told me why, and so it is quite an useful read.<br />
<br />
<u><b>Note about the code</b></u>:<br />
I quickly wrote this just to test the performance, and not production quality in mind. If you read the code, you can see I am sending 20 requests at a time, inside an infinite loop to retrieve all the pages. I exit the loop when any one of the pages, returns no result. I haven't tried <i>ExecuteMultipleRequest</i> inside the <i>Parallel.ForEach</i>. It would be interesting to see what the performance will be in that case.<br />
<ol style="text-align: left;">
</ol>
<u><b>Code</b></u>: Here is the code, I tested with, for reference.<br />
<br />
<pre class="prettyprint">using Microsoft.Pfe.Xrm;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Playground
{
class Program
{
static void Main(string[] args)
{
RetrieveAllPages(@"<fetch count='5000' no-lock='true' page='{0}' >
<entity name='account' >
<attribute name='name' />
<order attribute='accountid' />
<filter>
<condition attribute='statecode' operator='eq' value='0' />
</filter>
</entity>
</fetch>");
RetrieveAllPages(@"<fetch count='5000' no-lock='true' page='{0}' >
<entity name='contact' >
<attribute name='fullname' />
<order attribute='contactid' />
<filter>
<condition attribute='statecode' operator='eq' value='0' />
</filter>
</entity>
</fetch>");
}
static void RetrieveAllPages(string fetchXml)
{
Console.WriteLine("Entity: {0}\n", XElement.Parse(fetchXml).Element("entity").Attribute("name").Value);
var organisationSvcManager = new OrganizationServiceManager(new Uri("CRMURL"),
"[username]", "[password]", "[domain]");
var crmSvc = new CrmServiceClient(new NetworkCredential("[username]", "[password]", "[domain]"), Microsoft.Xrm.Tooling.Connector.AuthenticationType.AD, "CRMURL", "80", "[Org]");
var isDone = false;
int pageStart = 1, pageEnd = 20;
if (crmSvc.IsReady)
{
var stopWatch = new Stopwatch();
stopWatch.Start();
var results = new List<Entity>();
while (!isDone)
{
IDictionary<string, QueryBase> queries = new Dictionary<string, QueryBase>();
//Console.WriteLine("Page {0} to {1}", pageStart, pageEnd);
for (int i = pageStart; i <= pageStart + 19; i++)
{
queries.Add(i.ToString(), new FetchExpression(string.Format(fetchXml, i)));
};
pageStart = pageEnd + 1;
pageEnd = pageStart + 19;
var threadNum = 1;
Parallel.ForEach(queries,
(query) =>
{
if (!isDone)
{
var pageResults = crmSvc.OrganizationServiceProxy.RetrieveMultiple(query.Value).Entities;
if (!pageResults.Any())
{
isDone = true;
return;
}
results.AddRange(pageResults);
}
});
}
Console.WriteLine(results.Count);
stopWatch.Stop();
Console.WriteLine("Parallel: Executed in {0} sec", stopWatch.ElapsedMilliseconds / 1000);
Console.WriteLine(results.Count / (stopWatch.ElapsedMilliseconds / 1000) + " per sec\n");
var resultCount = 0;
pageStart = 1;
pageEnd = 20;
stopWatch.Restart();
isDone = false;
while (!isDone)
{
//Console.WriteLine("Page {0} to {1}", pageStart, pageEnd);
var executeMultipleRequest = new ExecuteMultipleRequest
{
Requests = new OrganizationRequestCollection(),
Settings = new ExecuteMultipleSettings() { ContinueOnError = true, ReturnResponses = true }
};
for (var i = pageStart; i <= pageStart + 19; i++)
{
executeMultipleRequest.Requests.Add(new RetrieveMultipleRequest()
{
Query = new FetchExpression(string.Format(fetchXml, i))
});
};
var executeMultipleResponses = ((ExecuteMultipleResponse)crmSvc.OrganizationServiceProxy.Execute(executeMultipleRequest)).Responses.ToList();
executeMultipleResponses.ForEach(x =>
{
var executeMultipleResultEntities = ((RetrieveMultipleResponse) x.Response).EntityCollection.Entities;
if (!executeMultipleResultEntities.Any())
{
isDone = true;
return;
}
resultCount = resultCount + executeMultipleResultEntities.Count;
});
pageStart = pageEnd + 1;
pageEnd = pageStart + 19;
}
Console.WriteLine(resultCount);
stopWatch.Stop();
Console.WriteLine("ExecuteMultiple: Executed in {0} sec", stopWatch.ElapsedMilliseconds / 1000);
Console.WriteLine(results.Count / (stopWatch.ElapsedMilliseconds / 1000) + " per sec\n");
IDictionary<string, QueryBase> entityQuery = new Dictionary<string, QueryBase>();
entityQuery.Add("result", new FetchExpression(fetchXml));
stopWatch.Restart();
var queryResult = organisationSvcManager.ParallelProxy.RetrieveMultiple(entityQuery, true,
(pair, exception) => Console.WriteLine("{0} throwed {1}", pair.Key, exception.Message));
stopWatch.Stop();
Console.WriteLine(queryResult.Values.First().Entities.Count);
Console.WriteLine("PFE.Xrm: Executed in {0} sec", stopWatch.ElapsedMilliseconds / 1000);
Console.WriteLine(queryResult.Values.First().Entities.Count / (stopWatch.ElapsedMilliseconds / 1000) + " per sec\n");
resultCount = 0;
var pagedResults = new EntityCollection();
var fetchToQuery = new FetchXmlToQueryExpressionRequest {FetchXml = string.Format(fetchXml, 1)};
var retrieveQuery = ((FetchXmlToQueryExpressionResponse)crmSvc.OrganizationServiceProxy.Execute(fetchToQuery)).Query;
retrieveQuery.PageInfo = new PagingInfo {PageNumber = 1};
stopWatch.Restart();
do
{
pagedResults = crmSvc.OrganizationServiceProxy.RetrieveMultiple(retrieveQuery);
resultCount += pagedResults.Entities.Count;
retrieveQuery.PageInfo.PageNumber++;
retrieveQuery.PageInfo.PagingCookie = pagedResults.PagingCookie;
} while (pagedResults.MoreRecords);
Console.WriteLine(resultCount);
stopWatch.Stop();
Console.WriteLine("Paged RetrieveMultiple: Executed in {0} sec", stopWatch.ElapsedMilliseconds / 1000);
Console.WriteLine(resultCount / (stopWatch.ElapsedMilliseconds / 1000) + " per sec\n");
}
}
}
}
</pre>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-74183836483279559922015-05-14T21:43:00.001+10:002015-05-14T21:51:41.781+10:00New calculated field functions in CRMOnline Update 1<div dir="ltr" style="text-align: left;" trbidi="on">
I logged a suggestion in Connect long time back, about lack of DATEDIFF function option in calculated field (<a href="https://connect.microsoft.com/dynamicssuggestions/Feedback/Details/1086828">https://connect.microsoft.com/dynamicssuggestions/Feedback/Details/1086828</a>).<br />
<br />
Quite to my surprise, CRMOnline Update 1 (Carina) now has a bunch of new DATEDIFF functions. These are<br />
<ul style="text-align: left;">
<li>DIFFINDAYS</li>
<li>DIFFINHOURS</li>
<li>DIFFINMINUTES</li>
<li>DIFFINMONTHS</li>
<li>DIFFINWEEKS</li>
<li>DIFFINYEARS</li>
</ul>
There is also an additional function "NOW", that gives you the current datetime. According to <br />
<a href="https://youtu.be/NJgRctOncuA?t=855">https://youtu.be/NJgRctOncuA?t=855</a> "NOW" returns SQL Server UTC Time and not the user's local time. This is true, only if the datetime field is <i>Time Zone Independent</i>. If the datetime field is created as <i>User Local</i>, "NOW" returns user's local timezone.<br />
<br />
If you try to use NOW function in a datetime field with behaviour <i>Time Zone Independent</i>, you'll get "<i>You can only use a Time-Zone Independent Date Time type field</i>" error message.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAmhx3p_WZ6P-xEyF9eOLjn0Qo4Z2_6jxuWxRxsw4z6_iyIutWP8wFGzmRVcXoEjvSdcLko0eRXwcmshF_UDfhSwVmTPvLpfhfmWxEBm4SAA5xuEjazK2wM82pqKoEMRbGKzbm_UbbqLs/s1600/CalcField1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAmhx3p_WZ6P-xEyF9eOLjn0Qo4Z2_6jxuWxRxsw4z6_iyIutWP8wFGzmRVcXoEjvSdcLko0eRXwcmshF_UDfhSwVmTPvLpfhfmWxEBm4SAA5xuEjazK2wM82pqKoEMRbGKzbm_UbbqLs/s640/CalcField1.png" width="640" /></a></div>
The trick to getting UTC time in this case, is to first create the datetime field as <i>User Local</i>, fill in the calculation field action, and only then change the datetime behaviour to <i>Time Zone Independent. </i>Also note that, it is possible to change the datetime behavior from <i>User Local </i>to <i>Time Zone Independent</i>, but not the other way around (from the UI).<br />
<br />
I created two calculated fields using NOW function, one is <i>User Local</i> and one is <i>Time Zone Independent. </i>After doing an Advanced Find with the attributes, here is the result.<br />
<i> </i><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxau_zhcVE1F7Hg0UC9KilIHeaADl8jfKZI-wk5YAYyli9KrVnaYCCQbT6y88jf9aVserjuhApAJOFIC_KeIb0MulPHBy6LAwGpUiuBnVPTOzNDyzTeOm0eXQpR14yHptiExUS9UThe8Q/s1600/CalcField2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxau_zhcVE1F7Hg0UC9KilIHeaADl8jfKZI-wk5YAYyli9KrVnaYCCQbT6y88jf9aVserjuhApAJOFIC_KeIb0MulPHBy6LAwGpUiuBnVPTOzNDyzTeOm0eXQpR14yHptiExUS9UThe8Q/s640/CalcField2.png" width="640" /></a></div>
<i> </i><br />
<i> </i><br />
DIFFINYEARS and NOW in combination, can be used in scenarios like calculating Age from Date of Birth, days since record creation, days to hit a certain deadline. These calculations, which were once accomplished by a running a periodic workflow or service, are trivial to implement with calculated fields. For eg. age calculation<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZJQslZpGszM88sMrA4Fdh4lH4djWEkSgFhkoPb1Va59WuethjkuKpwG4vRiLSfTA17hIMjVaHCAgxUqPP5a6uXbzOAyqZmDS1gq8iK4UbgunlnmGHOVHqUsiHvbuzTg4X-nsrl9aLW-s/s1600/CalcField3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZJQslZpGszM88sMrA4Fdh4lH4djWEkSgFhkoPb1Va59WuethjkuKpwG4vRiLSfTA17hIMjVaHCAgxUqPP5a6uXbzOAyqZmDS1gq8iK4UbgunlnmGHOVHqUsiHvbuzTg4X-nsrl9aLW-s/s640/CalcField3.png" width="640" /></a></div>
This is the Advanced Find result<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieYaDT3oeqhWYm4d62NK7nCWZJ_tyoSnGW9A9TYWcs8xNGEQMAUovGLzzTc3gF9g8cuupmKCmW5LSo-1d8DoIqHKBaI0jtbsiNUZjti9r3PRMSg0XMOdYPhnVFryoIHyatuotj0NZrJoA/s1600/CalcField4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieYaDT3oeqhWYm4d62NK7nCWZJ_tyoSnGW9A9TYWcs8xNGEQMAUovGLzzTc3gF9g8cuupmKCmW5LSo-1d8DoIqHKBaI0jtbsiNUZjti9r3PRMSg0XMOdYPhnVFryoIHyatuotj0NZrJoA/s640/CalcField4.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
These great additions in the Spring Update, make calculated fields more powerful than ever.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com5tag:blogger.com,1999:blog-5070296464471386188.post-63695362639880219642015-05-06T21:03:00.000+10:002015-05-06T21:03:33.005+10:00Plugin Registration Tool and Plugin Profile<div dir="ltr" style="text-align: left;" trbidi="on">
Having spent most of today trying out a failed plugin experiment, I discovered a feature of Plugin Registration tool that I never used before. It it not very clear from the SDK documentation, what keys are there in the InputParameters and OutputParameters and often I refer the appropriate request/response class, to find out what key I should be using on the InputParameter e.g. for UpdateRequest use Target key on the InputParameter for a pre-operation plugin.<br />
<br />
There seems to be a easier way to capture the plugin state right after the plugin fires. This can be done using the Plugin Registration tool. This is the plugin command bar:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9LT3EjFfzuyAjeGtL5BaJIGYKoJdcFk1h2PRqOoUwJpUU3Wd-YU_xPIOIinEv8ukZl5ug_-nsJcEjfQn6PCBjpLY3Aw2WaDvW2e4PIWkbFAp9xLpuIuiLaZIt93m9qO4QwFnlq1FLHGQ/s1600/PluginRibbon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9LT3EjFfzuyAjeGtL5BaJIGYKoJdcFk1h2PRqOoUwJpUU3Wd-YU_xPIOIinEv8ukZl5ug_-nsJcEjfQn6PCBjpLY3Aw2WaDvW2e4PIWkbFAp9xLpuIuiLaZIt93m9qO4QwFnlq1FLHGQ/s1600/PluginRibbon.png" height="56" width="640" /></a></div>
<br />
Replay Plug-in Execution button is used when you want to debug the plugin in Visual Studio. This process is well documented in multiple blogs and SDK documentation. View Plug-in profile functionality is what we want to use during the initial plugin development stage. After registering a plugin, right click on the desired step and choose Start Profiling.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0q48gth12CJZUGVsTdAZTB262M8zAQZmoxma6_HXPBZnVNXPRtchzhsYzRCFu8fAYf2gblRR2EODvZ4f1US2hcEDlL-hZmTzdquZ0c5626Zcw2PJMAbzo045xpcEbf6B40mk9JJGL9hA/s1600/Profile.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0q48gth12CJZUGVsTdAZTB262M8zAQZmoxma6_HXPBZnVNXPRtchzhsYzRCFu8fAYf2gblRR2EODvZ4f1US2hcEDlL-hZmTzdquZ0c5626Zcw2PJMAbzo045xpcEbf6B40mk9JJGL9hA/s1600/Profile.png" height="320" width="264" /></a></div>
Persist the profile to entity, instead of throwing an exception.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAd_2IOUhvy5bXPZvVG977rb1r1tSOIq2JarCmxe-qPiRiu9n2tlI9-bH3CsjvwCbseLe3UHQdG6rpyYkg1kJBlTVj6pfRJuorYTnQoQqkss8HJ8Pl9CD8JmrNOxHqrVvdFigXsa0YOSA/s1600/ProfileSettings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAd_2IOUhvy5bXPZvVG977rb1r1tSOIq2JarCmxe-qPiRiu9n2tlI9-bH3CsjvwCbseLe3UHQdG6rpyYkg1kJBlTVj6pfRJuorYTnQoQqkss8HJ8Pl9CD8JmrNOxHqrVvdFigXsa0YOSA/s1600/ProfileSettings.png" height="546" width="640" /></a></div>
<br />
Once this is done, perform the action that triggers the plugin. This creates a profile record, that we can use to dump the plugin state. After the plugin has finished executing, click the view plugin profile button in the command bar. It brings up this window.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhICAKbOSKE1GOSFM17pJkAfUXnkDokwM80LO-eqHHOUDKSTdWO8i8WQ87RRJI0Lpi2BuXBQoc8qS6_DmotH_TCGMR4yLICJ76xeodCnNT3XSYdlvhGgVPtofqZD26yQBff7m5DEItdOWo/s1600/PluginProfile.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhICAKbOSKE1GOSFM17pJkAfUXnkDokwM80LO-eqHHOUDKSTdWO8i8WQ87RRJI0Lpi2BuXBQoc8qS6_DmotH_TCGMR4yLICJ76xeodCnNT3XSYdlvhGgVPtofqZD26yQBff7m5DEItdOWo/s1600/PluginProfile.png" height="392" width="640" /></a></div>
<br />
Next, click the downarrow button and choose the appropriate trace record.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNmEGKrfjngKp_aj4YqJTFUd2wKgJffk7GYqWN8IMESyKkS6GLOYgIgceMzwi13hnvuCBemVV1rhuKsXQ-7AOweGCkli_lmSDeTwza5i6AT_X1TIxzogahKE_-H8Z6cewGKKB9GcG2ns/s1600/SelectProfile.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpNmEGKrfjngKp_aj4YqJTFUd2wKgJffk7GYqWN8IMESyKkS6GLOYgIgceMzwi13hnvuCBemVV1rhuKsXQ-7AOweGCkli_lmSDeTwza5i6AT_X1TIxzogahKE_-H8Z6cewGKKB9GcG2ns/s1600/SelectProfile.png" height="474" width="640" /></a></div>
<br />
After clicking the View button, you can see the entire plugin state. The below is the xml I got for a plugin firing on Retrieve message on SavedQuery.<br />
<br />
<pre class="prettyprint"><Profile>
<Configuration i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ConstructorDurationInMilliseconds>2</ConstructorDurationInMilliseconds>
<ConstructorException i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ConstructorStartTime>2015-05-06T01:46:45.5675566Z</ConstructorStartTime>
<Context>
<z:anyType i:type="PluginExecutionContext" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BusinessUnitId>1f06daae-de79-e411-80bd-00155dc6799a</BusinessUnitId>
<CorrelationId>09993a86-41c8-40b7-bc4c-2717057b5408</CorrelationId>
<Depth>1</Depth>
<InitiatingUserId>af20daae-de79-e411-80bd-00155dc6799a</InitiatingUserId>
<InputParameters xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<a:KeyValuePairOfstringanyType>
<b:key>Target</b:key>
<b:value i:type="a:EntityReference">
<a:Id>00000000-0000-0000-00aa-000010001001</a:Id>
<a:LogicalName>savedquery</a:LogicalName>
<a:Name i:nil="true" />
</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>ColumnSet</b:key>
<b:value i:type="a:ColumnSet">
<a:AllColumns>false</a:AllColumns>
<a:Columns xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<c:string>fetchxml</c:string>
<c:string>name</c:string>
<c:string>description</c:string>
<c:string>returnedtypecode</c:string>
<c:string>layoutxml</c:string>
<c:string>savedqueryid</c:string>
<c:string>name</c:string>
<c:string>statecode</c:string>
<c:string>statuscode</c:string>
<c:string>ismanaged</c:string>
<c:string>iscustomizable</c:string>
</a:Columns>
</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>ReturnNotifications</b:key>
<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">true</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>RelatedEntitiesQuery</b:key>
<b:value i:nil="true" />
</a:KeyValuePairOfstringanyType>
</InputParameters>
<IsExecutingOffline>false</IsExecutingOffline>
<IsInTransaction>false</IsInTransaction>
<IsOfflinePlayback>false</IsOfflinePlayback>
<IsolationMode>2</IsolationMode>
<MessageName>Retrieve</MessageName>
<Mode>0</Mode>
<OperationCreatedOn>2015-05-06T01:46:45.5206856Z</OperationCreatedOn>
<OperationId>00000000-0000-0000-0000-000000000000</OperationId>
<OrganizationId>a240c2fd-16a0-4ab5-9ecb-a43a6afdcc8c</OrganizationId>
<OrganizationName>Contoso</OrganizationName>
<OutputParameters xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<a:KeyValuePairOfstringanyType>
<b:key>BusinessEntity</b:key>
<b:value i:type="a:Entity">
<a:Attributes>
<a:KeyValuePairOfstringanyType>
<b:key>savedqueryid</b:key>
<b:value i:type="z:guid">00000000-0000-0000-00aa-000010001001</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>fetchxml</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema"><fetch version="1.0" output-format="xml-platform" mapping="logical"><entity name="account"><attribute name="name" /><attribute name="address1_city" /><order attribute="name" descending="false" /><filter type="and"><condition attribute="ownerid" operator="eq-userid" /><condition attribute="statecode" operator="eq" value="0" /></filter><attribute name="primarycontactid" /><attribute name="telephone1" /><attribute name="accountid" /><link-entity alias="accountprimarycontactidcontactcontactid" name="contact" from="contactid" to="primarycontactid" link-type="outer" visible="false"><attribute name="emailaddress1" /></link-entity></entity></fetch></b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>returnedtypecode</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">account</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>name</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">My Active Accounts</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>statuscode</b:key>
<b:value i:type="a:OptionSetValue">
<a:Value>1</a:Value>
</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>iscustomizable</b:key>
<b:value i:type="a:BooleanManagedProperty">
<a:CanBeChanged>true</a:CanBeChanged>
<a:ManagedPropertyLogicalName>iscustomizableanddeletable</a:ManagedPropertyLogicalName>
<a:Value>true</a:Value>
</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>layoutxml</b:key>
<b:value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema"><grid name="resultset" object="1" jump="name" select="1" icon="1" preview="1"><row name="result" id="accountid"><cell name="name" width="300" /><cell name="telephone1" width="100" /><cell name="address1_city" width="100" /><cell name="primarycontactid" width="150" /><cell name="accountprimarycontactidcontactcontactid.emailaddress1" width="150" disableSorting="1" /></row></grid></b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>ismanaged</b:key>
<b:value i:type="c:boolean" xmlns:c="http://www.w3.org/2001/XMLSchema">true</b:value>
</a:KeyValuePairOfstringanyType>
<a:KeyValuePairOfstringanyType>
<b:key>statecode</b:key>
<b:value i:type="a:OptionSetValue">
<a:Value>0</a:Value>
</b:value>
</a:KeyValuePairOfstringanyType>
</a:Attributes>
<a:EntityState i:nil="true" />
<a:FormattedValues>
<a:KeyValuePairOfstringstring>
<b:key>returnedtypecode</b:key>
<b:value>Account</b:value>
</a:KeyValuePairOfstringstring>
<a:KeyValuePairOfstringstring>
<b:key>statuscode</b:key>
<b:value>Active</b:value>
</a:KeyValuePairOfstringstring>
<a:KeyValuePairOfstringstring>
<b:key>iscustomizable</b:key>
<b:value>True</b:value>
</a:KeyValuePairOfstringstring>
<a:KeyValuePairOfstringstring>
<b:key>ismanaged</b:key>
<b:value>Managed</b:value>
</a:KeyValuePairOfstringstring>
<a:KeyValuePairOfstringstring>
<b:key>statecode</b:key>
<b:value>Active</b:value>
</a:KeyValuePairOfstringstring>
</a:FormattedValues>
<a:Id>00000000-0000-0000-00aa-000010001001</a:Id>
<a:LogicalName>savedquery</a:LogicalName>
<a:RelatedEntities />
</b:value>
</a:KeyValuePairOfstringanyType>
</OutputParameters>
<OwningExtension xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">
<a:Id>517294bb-91f3-e411-80d0-00155dc6799a</a:Id>
<a:LogicalName>sdkmessageprocessingstep</a:LogicalName>
<a:Name>RYR.VirtualViews.SavedQueryOnRetrieveMultiplePlugin: Retrieve of savedquery (Profiler)</a:Name>
</OwningExtension>
<PostEntityImages xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<PreEntityImages xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<PrimaryEntityId>00000000-0000-0000-00aa-000010001001</PrimaryEntityId>
<PrimaryEntityName>savedquery</PrimaryEntityName>
<RequestId i:nil="true" />
<SecondaryEntityName>none</SecondaryEntityName>
<SharedVariables xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<UserId>af20daae-de79-e411-80bd-00155dc6799a</UserId>
<ParentContext i:nil="true" />
<Stage>40</Stage>
</z:anyType>
</Context>
<ExecutionDurationInMilliseconds>8</ExecutionDurationInMilliseconds>
<ExecutionException i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<ExecutionStartTime>2015-05-06T01:46:45.5675566Z</ExecutionStartTime>
<HasServiceEndpointNotificationService>true</HasServiceEndpointNotificationService>
<IsContextReplay>false</IsContextReplay>
<IsolationMode>2</IsolationMode>
<OperationType>Plugin</OperationType>
<ProfileVersion>1.1</ProfileVersion>
<ReplayEvents xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<SecureConfiguration i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
<TypeName>RYR.VirtualViews.SavedQueryOnRetrieveMultiplePlugin</TypeName>
<WorkflowInputParameters xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<WorkflowOutputParameters xmlns:a="http://schemas.datacontract.org/2004/07/PluginProfiler.Plugins" />
<WorkflowStepId i:nil="true" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
</Profile>
</pre>
<br />
As you can see, this file is quite useful in trying to understand the plugin execution context and can be beneficial in the initial development stage. This feature has been in PluginRegistration tool since CRM2011, and I felt like an idiot for having just discovered it, but happy that I finally discovered this. I will definitely be using this a lot in the coming days.<br />
<br /></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-7615535453792353922015-04-29T21:10:00.000+10:002015-04-29T21:10:34.476+10:00Using actions to avoid intermediate entity<div dir="ltr" style="text-align: left;" trbidi="on">
When actions were first introduced into Dynamics CRM, I did not quite understand its potential and appreciate how useful they are. But after using actions in quite a few projects, I am true believer of actions. One scenario, where I found actions quite useful is, when you have a intermediate entity, just for triggering a workflow, actions can be used to eliminate the unnecessary entity.<br />
<br />
Here a (somewhat) simplified version of an design I worked on recently.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6COUFbJDlZlz6g_umeyOzvUvV0PDEXavFaZ8ZBXupm2Ufsnpk4fkAwjKgvViB33FIgkwIA59xBw6HBUNsfWDR5jHs8s6k2EcSM5er7CxdqXD2T6wZzn8gzf_U8_2du2TBIw-FvVfmwFI/s1600/Presentation1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6COUFbJDlZlz6g_umeyOzvUvV0PDEXavFaZ8ZBXupm2Ufsnpk4fkAwjKgvViB33FIgkwIA59xBw6HBUNsfWDR5jHs8s6k2EcSM5er7CxdqXD2T6wZzn8gzf_U8_2du2TBIw-FvVfmwFI/s1600/Presentation1.png" height="498" width="640" /></a></div>
<br />
The SSIS Job looks into <i>Invoice, Contact </i>and <i>Communication Configuration </i>entities and creates a <i>Communication </i>entity record. The <i>Communication</i> entity stores information from both <i>Contact </i>and <i>Invoice </i>entity. It also uses <i>Communication Configuration </i>entity to calculate a trigger date for sending the communication.<br />
<br />
In this design, the <i>Communication </i>entity exists solely for the <i>Send Communication </i>workflow. The entity itself doesn't serve any useful purpose beyond that. This entity has collated some information from <i>Invoice, Contact </i>and <i>Communication Configuration </i>entities and this is used by the <i>Send Communication </i>workflow.<br />
<br />
In this scenario the <i>Communication</i> entity can be replaced by an Action. Any attributes that are defined on the <i>Communication </i>entity, simply translate into input arguments on the action. The workflow that is triggered by create of <i>Communication</i> entity can simply be triggered from the Action. Once the <i>Communication</i> entity has been swapped over for an action, the SSIS task calls the action using a script task, instead of creating a <i>Communication </i>record.<br />
<br />
The only disadvantage I see of using this approach is that there is no historial information when you use action i.e. I can't simply use an Advanced Find to see when an action executed and with what parameters (unless you log it somewhere). I would get this capability if I used an entity, as I will store this information in the entity.<br />
<br /></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-7472772872214067322015-03-20T09:01:00.000+11:002015-03-20T09:01:29.111+11:00Opportunity Product Permissions<div dir="ltr" style="text-align: left;" trbidi="on">
When an assumption is made that something very basic, can be easily configured using OOB functionalities, that is when I find myself stuck occasionally and having to rethink on how to implement a feature. I recently had one such experience. The requirement was to allow users in certain security role, to delete opportunity<i> </i>products, but not opportunities.<br />
<br />
My first thought was to use security role, to modify the permissions for opportunity products. To my surprise, I was unable to find opportunity products in Security Role.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1-LVAy1u1_pETuk0TBSXvkm1J0rjSr0VUiLKKKi3QOCt-ukZvKIr_Ymj9QpHEkjQAFTpeS5dej7jbRy7u84ELjVMB-Sv0qrU818XAgHR2fLpRm-8n7M41J7n9xr1uFaxcBbEhqAIMTu4/s1600/SecurityRole.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1-LVAy1u1_pETuk0TBSXvkm1J0rjSr0VUiLKKKi3QOCt-ukZvKIr_Ymj9QpHEkjQAFTpeS5dej7jbRy7u84ELjVMB-Sv0qrU818XAgHR2fLpRm-8n7M41J7n9xr1uFaxcBbEhqAIMTu4/s1600/SecurityRole.png" height="56" width="640" /></a></div>
<br />
It turns out <i>Opportunity Product</i>, <i>Invoice Product</i>, <i>Quote Product</i> and <i>Order Product</i> share a unique trait: they don't have separate permissions and use the permission of their parent. Such being the limitation, I could implement this using ribbons or plugins. I implemented this using ribbon. Here are the steps<br />
<ol style="text-align: left;">
<li>Grant Delete permission on the Opportunity entity for the appropriate security role</li>
<li> Use <a href="http://ribbonworkbench.uservoice.com/knowledgebase/articles/80806-download-ribbon-workbench-for-crm-2011-2013-2015" target="_blank">Ribbon Workbench</a> to edit the ribbon for opportunity entity</li>
<li>Add a new Enable Rule of type Custom Javascript Rule. I am calling a function in the Javascript webresource<br /><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcnXGQYRlmZwm1uh8eHMPBKWE8DDGsTVv_G-D0gmydP_CqEDZa17F9uTbib64OSVh7mhyphenhyphen1HrgrUrzZmRSvW0Zg2a73wn4ow4H5FXbYl2bOtoiRRCUfnr_cKq50gDf0roikDE1JAyoCg00/s1600/Opportunity.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcnXGQYRlmZwm1uh8eHMPBKWE8DDGsTVv_G-D0gmydP_CqEDZa17F9uTbib64OSVh7mhyphenhyphen1HrgrUrzZmRSvW0Zg2a73wn4ow4H5FXbYl2bOtoiRRCUfnr_cKq50gDf0roikDE1JAyoCg00/s1600/Opportunity.png" height="272" width="640" /></a></div>
</li>
<li> Add the Enable Rule to the following commands: <i> </i></li>
<ul>
<li><i>Mscrm.DeletePrimaryRecord</i></li>
</ul>
<ul>
<li><i>Mscrm.DeleteSelectedRecord</i></li>
</ul>
<ul>
<li><i>Mscrm.HomePageGrid.DeleteSplitButtonCommand</i></li>
</ul>
</ol>
This change should be done on HomePage, Form and Subgrid ribbons. The code for the <i>getOppDeletePermissionByRole </i>itself is quite simple, as I am using XrmServiceToolkit.<br />
<br />
<pre class="prettyprint">var CVN = window.CVN || {};
CVN.getOppDeletePermissionByRole = function() {
return !XrmServiceToolkit.Soap.IsCurrentUserRole('1.1 CRM - Base User Role');
};
window.CVN = CVN;
</pre>
<br />
I did this on a CRM2011 organisation, but the process in same for a CRM2015 organisation. You'll just be editing the command bar instead of the ribbon. Here are the relevant buttons in CRM2015, whose command you'll need to edit.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTlw2PFPmmqEoQM9zm18mrH1S7OOMylYBAaC9mAnpQN5i7YtvrXYfA0zKzs01k_lPwg5xqDCfnYyMHO9XMy9Kgpgy3109DJ9BheEi4M9oV1XcyjiZ90wkcnHcg1N8HWq5ZCrBhVgW-sWk/s1600/CRM2015Command.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTlw2PFPmmqEoQM9zm18mrH1S7OOMylYBAaC9mAnpQN5i7YtvrXYfA0zKzs01k_lPwg5xqDCfnYyMHO9XMy9Kgpgy3109DJ9BheEi4M9oV1XcyjiZ90wkcnHcg1N8HWq5ZCrBhVgW-sWk/s1600/CRM2015Command.png" height="362" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtzbtYr-5Xa8ABKj4pSP49X4oNXpYYEjsTwsJVzFq-aaIX4z4mhiCYU0KIJfBQg-4HD7NEAj6BoH9nVZVr2cuGOtVi8MKzIZzclAQ4rRkQB4XSTlyWFSzG6KvrrqapC48ViK_yVxPff60/s1600/CRM2015Command.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br /></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-5672989835678466472015-03-18T08:21:00.001+11:002015-03-18T09:46:57.036+11:00Deploying a CRM2015 solution to CRM2013<div dir="ltr" style="text-align: left;" trbidi="on">
There have been some great posts recently on how to deploy a CRM2011/CRM2013 solution to CRM2015.<br />
<br />
1. Deepesh Somani -> <a href="https://dynamicsofdynamicscrm.wordpress.com/2014/12/05/issue-resolutionsolution-compatibility-crm-2013-to-crm-2015/">https://dynamicsofdynamicscrm.wordpress.com/2014/12/05/issue-resolutionsolution-compatibility-crm-2013-to-crm-2015/</a><br />
2. Andre Margono -> <a href="https://andz88.wordpress.com/2015/03/02/unsupported-customisation-importing-crm-2011-managed-solution-to-crm-2015/">https://andz88.wordpress.com/2015/03/02/unsupported-customisation-importing-crm-2011-managed-solution-to-crm-2015/</a><br />
<br />
I had recently to deploy one, the other way around: from CRMOnline to a CRM2013 instance. In my case the solution contained only html, png and Javascript webresources. The entity dependencies for the solution, were already present in the CRM2013 organisation. The CRM2013 organisation was on SP1 UR1 (6.1.1). Refer to <a href="https://support.microsoft.com/en-us/kb/2917899" target="_blank">https://support.microsoft.com/en-us/kb/2917899</a> if you are on a higher/lower rollup and modify the version number appropriately.<br />
<br />
In order to import the CRMOnline solution I had to<br />
<br />
1. Extract the solution zip file<br />
<br />
2. Change the first line of the <u><i>solution.xml</i></u> <b>from </b>'<i><ImportExportXml version="7.0.0000.5026" SolutionPackageVersion="7.0" languagecode="1033" generatedBy="CrmLive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></i>' <b>to </b>'<i><ImportExportXml version="6.1.0001.0132" SolutionPackageVersion="6.1" languagecode="1033" generatedBy="CrmLive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></i>'<br />
<br />
3.Delete <i><IsEnabledForMobileClient>0</IsEnabledForMobileClient></i> from every single webresource node in <u><i>customizations.xml</i></u><br />
<br />
4. Rezip the files<br />
<br />
After performing these steps, I was able to import the solution into the CRM2013 environment. As with the other two posts, this is an <b><u>unsupported</u></b> method, so use it at your own risk.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-64612904660277490582015-03-11T14:30:00.001+11:002015-03-11T14:30:29.203+11:00Create New User Error<div dir="ltr" style="text-align: left;" trbidi="on">
Yesterday, I got the following error when I tried to add a new user:<br />
<br />
<i>You are attempting to create a user with a domain logon that is already used by another user. Select another domain logon and try again.</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2z-gTgi3sctOkYu4BTSSDOQG1O2iduFanOO39oO_9GvLBLLvOLyEwclFDIWJ54DkAqsckKJiPihnlI9xMY6AeK3Y4pP_NEMvOHZCJIpggLK9j39wlIqYHV6BwADFtN_Qi6ppuHVOVT9E/s1600/NewUserError.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2z-gTgi3sctOkYu4BTSSDOQG1O2iduFanOO39oO_9GvLBLLvOLyEwclFDIWJ54DkAqsckKJiPihnlI9xMY6AeK3Y4pP_NEMvOHZCJIpggLK9j39wlIqYHV6BwADFtN_Qi6ppuHVOVT9E/s1600/NewUserError.png" height="310" width="640" /></a></div>
<br />
The strange thing I noticed about the error is that, the user I was trying to add was not already there in CRM. I checked this in the <i>SystemUser </i>table and confirmed that it is definitely not there. After tracing SQL Server, I found CRM uses <i>SystemUserAuthentication</i> table to do this check.<br />
<br />
Here is the sequence to events<br />
<br />
No user A -> Backup organisation database -> User A created -> Restore organisation db from backup<br />
<br />
In my situation, the error started happening after I restored the organisation db from the backup. At the time of the backup, the user I was trying to add had not been created. After the organisation db was restored from backup, the <i>SystemUser </i>table in the organisation database does not contain User A, but the <i>MSCRM_CONFIG</i> does (as per <i>SystemUserAuthentication</i>). This is the root cause of this error message.<br />
<br />
The fix was to delete the organisation and re-import the organisation from the Deployment Manager. Once this is done, the new user can be added without any issue. This was the additional step I had to perform after I restored the db from the backup.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-74171616168197906332015-02-21T22:24:00.002+11:002015-02-21T22:35:28.769+11:00Bug: Limitation of Action EntityReference Input Argument<div dir="ltr" style="text-align: left;" trbidi="on">
Actions are great for lot of things, but there are few bugs/limitations that I experienced and found particularly frustrating. One of such bugs is that you cannot use the attributes of an entityreference input argument on an action step. This is not the same with custom workflow step with an entityreference output. You would be able to use any attribute from the entityreference output off the custom workflow step.<br />
<br />
Here is the action definition<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ51_ynYL7P216jCCEqGk3rriOjKIBN6z4YFpX1Vp7HSYSOSkhJ2ukpsM1gyMu2k-OTrFJF_O9qkZKRr-FgGcpEqwv6-o_0aKWYExJzh7p1efDAIt4BPs-GgS-DogT8-C4H1Lwl-cpoaw/s1600/Action1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ51_ynYL7P216jCCEqGk3rriOjKIBN6z4YFpX1Vp7HSYSOSkhJ2ukpsM1gyMu2k-OTrFJF_O9qkZKRr-FgGcpEqwv6-o_0aKWYExJzh7p1efDAIt4BPs-GgS-DogT8-C4H1Lwl-cpoaw/s1600/Action1.png" height="342" width="640" /></a></div>
<br />
The entityreference action argument is available in the dropdown and all the properties appear as if they can be used.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikSOrHPd8LOrEBAqPDiRw8OpmfZRvOq4jdmwxOvys5wwHmaxeI8T54EWWNSR_7iD2IJUT9LFkUpJ21NfVhfWkoQoYK7QAdhSKMocHGlodGgUpq6aSU70MeMydlWG9EJ-IDx8FlGeOee_8/s1600/Action6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikSOrHPd8LOrEBAqPDiRw8OpmfZRvOq4jdmwxOvys5wwHmaxeI8T54EWWNSR_7iD2IJUT9LFkUpJ21NfVhfWkoQoYK7QAdhSKMocHGlodGgUpq6aSU70MeMydlWG9EJ-IDx8FlGeOee_8/s1600/Action6.png" height="320" width="275" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is the create email step with values from workflow and action argument being used. </div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCPW6RBQJ8dqDhZU44Fkz_fxIrz7GI-22e1SjvLuWs7GBIinqrnPJw9LW_tgAQs4h7PKxzn8cTFF0rz9cINl_jawCP6mgLreIA-7d91MmzkEghgYkYEJ8cSPKnS5hcZUZ5VMFxuGwPA0g/s1600/Action3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCPW6RBQJ8dqDhZU44Fkz_fxIrz7GI-22e1SjvLuWs7GBIinqrnPJw9LW_tgAQs4h7PKxzn8cTFF0rz9cINl_jawCP6mgLreIA-7d91MmzkEghgYkYEJ8cSPKnS5hcZUZ5VMFxuGwPA0g/s1600/Action3.png" height="162" width="640" /></a></div>
<br />
I also have a custom workflow step that accepts an entityreference input and just sets the entityreference output.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7r0xipr8vWsFETd-iILgI8X3c9oqMLMI5oawOaHwFxZxI52BstclNRNddhDHQmfpkhWTd3aR_IegwnT8sEBBhPmP_mlUM8iePC2_VbOKSVrNZQZWcruWE2xqnuuVocefqYHH_jEY3pw0/s1600/Action4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7r0xipr8vWsFETd-iILgI8X3c9oqMLMI5oawOaHwFxZxI52BstclNRNddhDHQmfpkhWTd3aR_IegwnT8sEBBhPmP_mlUM8iePC2_VbOKSVrNZQZWcruWE2xqnuuVocefqYHH_jEY3pw0/s1600/Action4.png" height="164" width="640" /></a></div>
<br />
The custom workflow step input is set the action input argument.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjCuvKVGugBVi9tn771dB6r6k7Xa3Unc7OkvupPe9y1yTP9zuBY1uuqDeC5Q1Nap7E6j_q3EQa9h80jboPDgyFR7nie0s3pezjYUkzsaeyp9CLke3G_hq9X6uYgZZpXg2-Tx1ST31pFOo/s1600/Action7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjCuvKVGugBVi9tn771dB6r6k7Xa3Unc7OkvupPe9y1yTP9zuBY1uuqDeC5Q1Nap7E6j_q3EQa9h80jboPDgyFR7nie0s3pezjYUkzsaeyp9CLke3G_hq9X6uYgZZpXg2-Tx1ST31pFOo/s1600/Action7.png" height="88" width="400" /></a></div>
<br />
<br />
This code for the custom workflow step is quite simple.<br />
<br />
<pre class="prettyprint">using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;
namespace TestWorkflows
{
public sealed class ActionParameterToContactEntityReference : CodeActivity
{
[Input("Contact")]
[ReferenceTarget("contact")]
[RequiredArgument]
public InArgument<EntityReference> ContactInput { get; set; }
[Output("Contact")]
[ReferenceTarget("contact")]
public OutArgument<EntityReference> ContactOutput { get; set; }
protected override void Execute(CodeActivityContext executionContext)
{
ContactOutput.Set(executionContext, ContactInput.Get(executionContext));
}
}
}
</pre>
<br />
This is the email activity after the action is created.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Gn9uhw6jxCIur5HXRLBiqanLd04HzvuGQXz7n71yInu0vP6TfosyzLjd6W1AvGURLqxQ_QqkzoxPLox_nRhNrrIEGsdCTIRSnfOxGBVgrfPtWgXmv6yDVbIb3gnJYr1mIsI_K_vx2AA/s1600/Action5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_Gn9uhw6jxCIur5HXRLBiqanLd04HzvuGQXz7n71yInu0vP6TfosyzLjd6W1AvGURLqxQ_QqkzoxPLox_nRhNrrIEGsdCTIRSnfOxGBVgrfPtWgXmv6yDVbIb3gnJYr1mIsI_K_vx2AA/s1600/Action5.png" height="304" width="640" /></a></div>
<br />
<br />
As you can see, the Email and Firstname properties from the action's input entity reference comeup as blank, but there is no such issue with the ones retrieved from the custom workflow step.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-66762332491454820112015-01-28T20:35:00.001+11:002015-01-28T20:35:46.946+11:00Bookmarklet to copy FetchXml<div dir="ltr" style="text-align: left;" trbidi="on">
This is basically an extension of this post -> <a href="http://nycrmdev.blogspot.com.au/2014/12/using-advanced-find-fetchxml-capability.html" target="_blank">http://nycrmdev.blogspot.com.au/2014/12/using-advanced-find-fetchxml-capability.html</a>. The bookmarklet below displays fetchxml that was used to display the results.<br />
<br />
<pre class="prettyprint">javascript:var fetchXml;if(frames[0]&&frames[0].document.getElementById('FetchXml')){fetchXml=frames[0].document.getElementById('FetchXml').value;} else if(frames[1]&&frames[1].document.getElementById('FetchXml')){fetchXml=frames[1].document.getElementById('FetchXml').value;} if(fetchXml){window.prompt('FetchXml',fetchXml);} else{alert('No FetchXml query found');} void 0;
</pre>
<br />
Run this bookmarket from the Advanced Find results page and it will display the FetchXml in a dialog window for copy pasting.<br />
<br />
<img alt="" height="237" src="data:image/png;base64,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" width="400" /><br />
<br />
Sometimes I just want to develop a starting point fetchxml using advanced find and work on it more using FetchXml Builder or Fetch Tester 3000. This bookmarklet saves me the hassle of exporting the fetchxml file, and copy pasting the result into the appropriate tool.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-7306079118827523402015-01-27T21:35:00.000+11:002015-01-27T21:35:25.391+11:00Notes Control in CRM 2013 SP1<div dir="ltr" style="text-align: left;" trbidi="on">
If you have a note control on a form and the default tab on this note control is Notes, no note records might be displayed, even though there are notes that are related to the record. Once you click the Notes link on the form, you'll suddenly see notes being populated. This is a bug that has been fixed in 6.1.1.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2kbJEaiD2OaldPNmmalVrfgaUbvb8RtKOs0Q-iDKEz0Wok6hEtZFQjIgI3yKJtoVp307pnKEk__tR51k0nKJOUZ86HRUo7fGKl27h4vfzJ7R2ci902r5WMMa-A9kVBED45d6NT0atvQM/s1600/Default+Tab.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2kbJEaiD2OaldPNmmalVrfgaUbvb8RtKOs0Q-iDKEz0Wok6hEtZFQjIgI3yKJtoVp307pnKEk__tR51k0nKJOUZ86HRUo7fGKl27h4vfzJ7R2ci902r5WMMa-A9kVBED45d6NT0atvQM/s1600/Default+Tab.png" height="338" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2xmcKnSwQqi6hHDwPWt1xBUNrZ3BnNzPNh88zPD_ajmrkQ6pYI9-IOOYd0JCfQWsb9YSszQnfctTuWWXDKGQ3wxFcsFbh1unjl-TFd_Yc1-qNtVs1RBszzWyi6WSAdnC7qgVogez5dw0/s1600/Notes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2xmcKnSwQqi6hHDwPWt1xBUNrZ3BnNzPNh88zPD_ajmrkQ6pYI9-IOOYd0JCfQWsb9YSszQnfctTuWWXDKGQ3wxFcsFbh1unjl-TFd_Yc1-qNtVs1RBszzWyi6WSAdnC7qgVogez5dw0/s1600/Notes.png" height="456" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
In order to automatically click the Notes link, I have a small script running in the onLoad event of the form to fix this issue on CRM 2013 SP1. This script is a stop gap measure, till 6.1.1 is applied to the server.<br />
<br />
<pre class="prettyprint">setTimeout("(function() { var t = document.querySelector('.tabLink.active'); if(t) { t.click(); } })();",2000);
</pre>
<br />
This issue doesn't seem to be happening in CRM2013 SP1 UR1 and CRM2015 and hence this (<u><b>unsupported</b></u>) fix is not applicable to these versions.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com2tag:blogger.com,1999:blog-5070296464471386188.post-257372308054123172015-01-27T20:56:00.003+11:002015-01-29T08:20:52.389+11:00GetAttributeValue and null DateTime<div dir="ltr" style="text-align: left;" trbidi="on">
Previously, I used to access the value of a property like entity["attributename"] and cast the result into the appropriate type. The preceding line to this, would always be a check to see if the property exists, as it can cause a KeyNotFoundException, without this check. <i>GetAttributeValue </i>is how I access attribute values these days. These are some influential posts that made me change my behaviour.<br />
<br />
David Berry -> <a href="http://crmentropy.blogspot.com.au/2013/08/entitygetattributevalue-explained.html" target="_blank">http://crmentropy.blogspot.com.au/2013/08/entitygetattributevalue-explained.html</a><br />
Guido Preite -> <a href="http://www.crmanswers.net/2014/09/getattributevalue-activityparty.html" target="_blank">http://www.crmanswers.net/2014/09/getattributevalue-activityparty.html</a><br />
<br />
While this does prevent KeyNotFoundException, it is important to understand the behaviour of <i>GetAttributeValue</i>, w.r.t DateTime. When <i>GetAttributeValue </i>is invoked to retrieve a DateTime attribute, and the value of the attribute is null, it returns a <i>DateTime.MinValue</i>, which is 01/01/0001.<br />
<br />
In a scenario where a retrieved value is used to update another record, you'll have to check if this is <i>DateTime.MinValue</i> before updating, or it will cause an exception like the one below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdSz7WCl8j_zWAmhpjysgRKXinzry-nqD84Ej-vhO2oApfT3nCN1bGjA17dE6eEmHZ5bmKI2G3J9Jc2dU4uWcGWw17H1HaUBq3ltbK3q0TNQoIEmlZerclWcMPo7ieLrue6u0OvbR5Ug8/s1600/WorkflowError.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdSz7WCl8j_zWAmhpjysgRKXinzry-nqD84Ej-vhO2oApfT3nCN1bGjA17dE6eEmHZ5bmKI2G3J9Jc2dU4uWcGWw17H1HaUBq3ltbK3q0TNQoIEmlZerclWcMPo7ieLrue6u0OvbR5Ug8/s1600/WorkflowError.png" height="179" width="640" /></a></div>
The exception thrown is "DateTime is less than minumum[<i>sic</i>] value supported by CrmDateTime. Actual value: 01/01/0001 11:00:00, Minimum value supported: 01/01/1900 00:00:00". To prevent this exception, I check if the retrieved DateTime value == DateTime.MinValue, and if so, choose not to update the target property, or set it as null, depending on the requirement. It is also a realisation for me, that <i>CrmDateTime </i>still lives on, somewhere in the Sdk assemblies.<br />
<br />
<b>EDIT (29/01/15):</b> Following David's tip from the comment below, the better approach is to use nullable types with <i>GetAttributeValue</i>, so I should be using DateTime? instead of DateTime.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com5tag:blogger.com,1999:blog-5070296464471386188.post-49834870217688365722015-01-21T19:10:00.000+11:002015-03-20T09:17:57.164+11:00Quick Tip: Don't use underscore in Action argument name<div dir="ltr" style="text-align: left;" trbidi="on">
There seems to be a bug in the process editor, when you use it to define an action that contains an argument with an underscore in the name. Once you save this action, which meets this criteria, you will not be able to open the action definition again through the process editor. You just get a generic error dialog when you try to open the action.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz7YxmBratVEuN99c69E2-LgI45KmqbsREdjdn8zQNPgxy5q2QPiOEKeF3L35dpY75nUj_mLmTvaP9nRNG2L6AT5raVwZZuvFR6QfNsNZINW7Q0pL5ydefmBaOzrfW9gmaW67LXwm0CEI/s1600/UnexpectedError.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz7YxmBratVEuN99c69E2-LgI45KmqbsREdjdn8zQNPgxy5q2QPiOEKeF3L35dpY75nUj_mLmTvaP9nRNG2L6AT5raVwZZuvFR6QfNsNZINW7Q0pL5ydefmBaOzrfW9gmaW67LXwm0CEI/s1600/UnexpectedError.png" height="306" width="640" /></a></div>
<br />
My action definition itself is minimal. It doesn't contain anything other than the argument (screenshot after following recovery steps).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEPPysrk1PpaChHawgStSTRE83SSoWPC0OixF1DKP4mKuOzkuDLffgxvmqkU1BhcxqA__rdh7Pp2NV4vaX9B4WP34mM1QnJ1fOfuU8ZFQvOv69cVkL12idtrNHdRyp7_Kbm5jE4BiSIu0/s1600/action.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEPPysrk1PpaChHawgStSTRE83SSoWPC0OixF1DKP4mKuOzkuDLffgxvmqkU1BhcxqA__rdh7Pp2NV4vaX9B4WP34mM1QnJ1fOfuU8ZFQvOv69cVkL12idtrNHdRyp7_Kbm5jE4BiSIu0/s1600/action.png" height="456" width="640" /></a></div>
<br />
The underlying error that is found in the url is:<br />
<br />
Error code: 0x80040216<br />
Error description: Invalid variable name format<br />
<br />
In order to recover from the error follow these steps<br />
<br />
1.) Create a new solution and add the action to this solution<br />
2.) Export the solution as an unmanaged solution<br />
3.) Unzip the solution to a location<br />
4.) In the workflow folder, you will find a xaml file. Open this using any text editor<br />
5.) Find and replace the parameter name which has the underscore, to be without underscore<br />
6.) Rezip and import<br />
<br />
The action can be opened again after following these steps. I tested this issue and can confirm that it happens in CRM 2013 6.1.1 and CRM Online.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-88422657832625150752015-01-19T20:52:00.000+11:002015-01-19T20:52:12.349+11:00Business Rules by Form Type<div dir="ltr" style="text-align: left;" trbidi="on">
<i>Xrm.Page.ui.getFormType()</i> is used in form script to find out what type of form is currently loaded. Sometimes, we want to apply a certain logic, depending on whether it is a create form or update form. e.g I want to disable some fields, if it is an update form. If we are using Business Rules, it is not very obvious (at least to me) on how this can be achieved. The answer is quite simple: just check the value of any of these system fields (created, createdon, modifiedby, modifiedon). Here is a business rule that will trigger only for update form.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3NGOw8Pus8Tl5-PZpAtxia5oKe1SVI5x_8pXmSHjapLheDDT8AlRGSD7WsLE4ruRReB4Ug4uq3gMbz3GFreKnc8q59lAQUk_3iPkbtjZsRDtlA58QOpJBIOTjKHcSO7xAid8DHHH2h-Q/s1600/UpdateOnlyBR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3NGOw8Pus8Tl5-PZpAtxia5oKe1SVI5x_8pXmSHjapLheDDT8AlRGSD7WsLE4ruRReB4Ug4uq3gMbz3GFreKnc8q59lAQUk_3iPkbtjZsRDtlA58QOpJBIOTjKHcSO7xAid8DHHH2h-Q/s1600/UpdateOnlyBR.png" height="204" width="640" /></a></div>
Here is the rule for create form.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxymkD5JxSKu6EG3QmckWku3DnvYJy2VKwGMQcJSlck2LVl6C01vchoIJBpuE9vaKXNi7AVik01-B43Jb52-zDibHoljbQWqbaeYC5-Hr0iviWN5C-BnUdZ5WjaZaSJkKnM3g1cC_YcNM/s1600/CreateOnlyBR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxymkD5JxSKu6EG3QmckWku3DnvYJy2VKwGMQcJSlck2LVl6C01vchoIJBpuE9vaKXNi7AVik01-B43Jb52-zDibHoljbQWqbaeYC5-Hr0iviWN5C-BnUdZ5WjaZaSJkKnM3g1cC_YcNM/s1600/CreateOnlyBR.png" height="210" width="640" /></a></div>
<br />
<br />
Here is the result after the rule has run on an existing record<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1DjNi-0vEnKmeTmN6szcAuLzBpqQjvWY9o5AX4JDiHTlaqROB-l3aZGoRs9XW-Vh4IQ5oYXXbRgqREn6DyDX1oR8Fb5m4tcvCQ8Z6-m9hI-t0YHliUMfVRJwfzw-hs2b3o_k2kgwL_rs/s1600/UpdateForm.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1DjNi-0vEnKmeTmN6szcAuLzBpqQjvWY9o5AX4JDiHTlaqROB-l3aZGoRs9XW-Vh4IQ5oYXXbRgqREn6DyDX1oR8Fb5m4tcvCQ8Z6-m9hI-t0YHliUMfVRJwfzw-hs2b3o_k2kgwL_rs/s1600/UpdateForm.png" height="200" width="640" /></a></div>
<br />
<br />
The important thing to remember is: <u>The system field you are checking (in this case createdon), has to be on the form. Otherwise the rule will not fire.</u><br />
<br />
Credits to @BernadoNH for this info.<br />
<blockquote class="twitter-tweet" data-partner="tweetdeck">
Business rule only runs if the fields are on the BODY section of the form <a href="https://twitter.com/hashtag/msdyncrm?src=hash">#msdyncrm</a>. Too risky - JavaScript feels like a better way to go.<br />
— Bernado Nguyen-Hoan (@BernadoNH) <a href="https://twitter.com/BernadoNH/status/557030803742269440">January 19, 2015</a></blockquote>
<script async="" charset="utf-8" src="//platform.twitter.com/widgets.js"></script>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1DjNi-0vEnKmeTmN6szcAuLzBpqQjvWY9o5AX4JDiHTlaqROB-l3aZGoRs9XW-Vh4IQ5oYXXbRgqREn6DyDX1oR8Fb5m4tcvCQ8Z6-m9hI-t0YHliUMfVRJwfzw-hs2b3o_k2kgwL_rs/s1600/UpdateForm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-34986063469080053722015-01-15T08:46:00.000+11:002015-01-15T09:29:38.968+11:00An alternative approach to loading form scripts in Dynamics CRM<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<span id="goog_620289488"></span><a href="https://www.blogger.com/"></a><span id="goog_620289489"></span>With each browser update, full ES6 support has been getting closer and closer. But this is still sometime away, and transpilers like traceur or 6to5 can help bridge the gap in some areas. One ES6 functionality I am very much interested in, is module. As of today, no browser natively supports this, and I would have to transpile my code to get this functionality.<br />
<br />
So, I once again would like to use my favorite module loader, requirejs for doing this. The last time I did this (<a href="http://nycrmdev.blogspot.com.au/2014/04/using-requirejs-in-crm2013.html" target="_blank">http://nycrmdev.blogspot.com.au/2014/04/using-requirejs-in-crm2013.html</a>) I had to use some unsupported tricks to get this working in CRM2013. This time, my approach is to do away with CRM script loading mechanism altogether and use requirejs to load the form scripts.<br />
<br />
Here is how my resources are organised.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW06Vy4Z21xax__hpv2qH4MyXt6s-uUeUxGXcMWnTOmdh6ZY5XWuD3h8WAu7KVlIo5q9DFtqTu1VHYdV-qRCClqBx59Vz-Gu7jNfyeQ2IopMepQ3KMgwisP23PAWBXgb3QcAudJ0gViik/s1600/Structure.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW06Vy4Z21xax__hpv2qH4MyXt6s-uUeUxGXcMWnTOmdh6ZY5XWuD3h8WAu7KVlIo5q9DFtqTu1VHYdV-qRCClqBx59Vz-Gu7jNfyeQ2IopMepQ3KMgwisP23PAWBXgb3QcAudJ0gViik/s1600/Structure.png" height="400" width="371" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Events.html is the HTML webresource that will be embedded in the entity form. Here is the code for events.html;</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="prettyprint"><!DOCTYPE html>
<html>
<head>
<title>Form Events</title>
<!-- data-main attribute tells require.js to load
scripts/main.js after require.js loads. -->
<script data-main="scripts/main" src="scripts/require.js"></script>
</head>
<body>
<ul id="events">
</ul>
</body>
</html>
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
main.js is the entry point into the form processing code.</div>
<br />
<pre class="prettyprint">(function () {
var defaultConfig = {
shim: {
'lodash': {
exports: '_'
}
},
deps: ['lodash', 'common', 'ryr_eventform'],
callback: function() {
console.log('callback before requirejs has been loaded');
},
onError: function(err) {
console.log(err.requireType);
if (err.requireType === 'timeout') {
console.log('modules: ' + err.requireModules);
}
throw err;
}
};
defaultConfig.callback = function() {
console.log('callback after requirejs has been loaded');
};
requirejs.config(defaultConfig);
})();
</pre>
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I want the scripts to load in the following order: lodash->common->ryr_eventform. If you use the form area to reference your script, you really don't have any control over the sequence, as they are loaded async and may not be loaded in the same order you added them in the form (<a href="http://www.develop1.net/public/post/Asynchronous-loading-of-JavaScript-Web-Resources-after-U12POLARIS.aspx" target="_blank">http://www.develop1.net/public/post/Asynchronous-loading-of-JavaScript-Web-Resources-after-U12POLARIS.aspx</a>). Until Microsoft changes this functionality, there are two ways to overcome this issue.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
1.) Bundle all your scripts in the order of their dependencies</div>
<div class="separator" style="clear: both; text-align: left;">
2.) Check if the dependency has loaded. (See the waitForScript technique in the develop1 link)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I am loading the scripts using requirejs, but the triggering page is an external web resource. This way I can keep this a supported method.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is common.js, which is required by ryr_eventform.js.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<pre class="prettyprint">define(['lodash'], function (_) {
var common = {
log: function(message) {
var e = document.createElement("li");
e.innerHTML = new Date().toString().split(' ')
.filter(function(d,i){ return i>0 && i<=4})
.join(' ') +': '+ message;
document.getElementById('events').appendChild(e);
}
};
common.log('Loading common_script.js');
//can use lodash, as it is specified as a dependency and should have been loaded
common.log('Lodash Version: '+_.VERSION);
return common;
});
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is ryr_eventform.js.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<pre class="prettyprint">define(['common', 'lodash'], function (common,_) {
common.log('Loading ryr_eventform.js');
//can use lodash, as it is specified as a dependency and should have been loaded
common.log('Lodash Version: '+_.VERSION);
var Xrm = parent.Xrm;
var form = {
onSave: function(context) {
common.log('Form Save Event');
},
onLoad: function() {
common.log('Form Load Event');
if(Xrm){
Xrm.Page.data.entity.addOnSave(this.onSave);
Xrm.Page.getAttribute('ryr_name').addOnChange(function(context) {
common.log('Name Change Event: ' + context.getEventSource().getValue());
});
}
else{
common.log('Web Resource has not been embedded inside a CRM form');
}
}
};
form.onLoad();
return form;
});
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is how the form looks in the design mode.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUgi7L-1btdVy8Zo2dkrh5JHIhW744hqKXzLga0iofz9ZzPGBC3h5uRa_CgDgMOnzmx2v6eJR-xFN7UyKyEDALZhrcwT8Tl8DfRhZYi-sMrlpJwUQEARK0I7GHu-gKnv-6iRW4Q9rFeLE/s1600/FormDesign.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUgi7L-1btdVy8Zo2dkrh5JHIhW744hqKXzLga0iofz9ZzPGBC3h5uRa_CgDgMOnzmx2v6eJR-xFN7UyKyEDALZhrcwT8Tl8DfRhZYi-sMrlpJwUQEARK0I7GHu-gKnv-6iRW4Q9rFeLE/s1600/FormDesign.png" height="350" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
I have not added any scripts to the form.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg2udbRrqkr7fkYlYBzxCsht4V93iz9PjK95A5HOUrGM_C54d1PzLtWkJ8KOgEoW0KENi2QM7zjWvZKUXLI6cOzMCp8q1l532OQcKlMvMqY6jjTeEceRBnmz_hG0p1nWSvHGXqM4DSaUU/s1600/FormLibs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg2udbRrqkr7fkYlYBzxCsht4V93iz9PjK95A5HOUrGM_C54d1PzLtWkJ8KOgEoW0KENi2QM7zjWvZKUXLI6cOzMCp8q1l532OQcKlMvMqY6jjTeEceRBnmz_hG0p1nWSvHGXqM4DSaUU/s1600/FormLibs.png" height="512" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Since requirejs will start loading the scripts, you don't need to worry about this.<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Lets start looking at some form events now and how the script behaves.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<b>Form Load</b></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsN2GBT4CA9insd3glVoQMYUWjJXRzASBW_5cSv3T6EAhe2wtdEiUu0ml5PlPiiYnhhI4RSCxcC9l2P-wuN2OT7Dovj6C8rIfvKJt5hkEAofT1WumKo5lf24RWBT0iIZO9gFab3DIXGcg/s1600/EventForm-Form+Loaded.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsN2GBT4CA9insd3glVoQMYUWjJXRzASBW_5cSv3T6EAhe2wtdEiUu0ml5PlPiiYnhhI4RSCxcC9l2P-wuN2OT7Dovj6C8rIfvKJt5hkEAofT1WumKo5lf24RWBT0iIZO9gFab3DIXGcg/s1600/EventForm-Form+Loaded.png" height="579" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
<b>Name field changed</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjDfE-3oDge-E6uu97N74TjKhbG2SjJJOD7XwxZFatSEOrVi6_lELQ7c7Oqt6FsRMLXA-7k-saNiG-YKrxLvUuRroDsfUl_1AFWfZBfjuZD_kwu-JpMKh-WyIpiG7BqKpSiB4z0bK2DVk/s1600/Event+Form-Field+Change.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjDfE-3oDge-E6uu97N74TjKhbG2SjJJOD7XwxZFatSEOrVi6_lELQ7c7Oqt6FsRMLXA-7k-saNiG-YKrxLvUuRroDsfUl_1AFWfZBfjuZD_kwu-JpMKh-WyIpiG7BqKpSiB4z0bK2DVk/s1600/Event+Form-Field+Change.png" height="446" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<b> </b>As you, can see a script can do exactly the same things, even though it has not been been loaded through the CRM form script loading mechanism. These are are two key things that help to achieve this.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
1.) The webresource folder structure</div>
<div class="separator" style="clear: both; text-align: left;">
2.) Referencing Xrm object from webresource using parent.Xrm</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The impetus for this post is this: I have got "The form has changed. Would you like to save your changes" dialog more than a few times and I have no idea what is the reason for this dialog. If the change has made by a script, I have no way of knowing what the change was, and which script triggered this, unless I have added some console.log message the scripts. This is not possible if I can't change the script. You could live edit the script using the DevTools, but I don't want to do that.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The disadvantages of this techique, that I can see are</div>
<ol style="text-align: left;">
<li>html webresource has to be added to the form</li>
<li>Tablet support </li>
</ol>
<div class="separator" style="clear: both; text-align: left;">
If CRM Client API exposes some sort of event listening capability, this would help the devs to listen to certain events like form save, form load, field onchange from the devtools console and figure out what is happening with the form, without using the debugger step through. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
CRM itself, uses custom events and listeners internally, to figure out what scripts to execute for a particular event. But this functionality is not exposed externally for everyone to use. Until this is made available down the line, into some sort of Client API - Dev Mode, I can use this to control the form script loading process and audit of form events.</div>
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-51530684282231655342014-12-18T21:30:00.000+11:002014-12-24T13:03:10.358+11:00Using Advanced Find FetchXml capability in custom forms<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
I prefer FetchXml compared to QueryExpression or LINQ when writing custom code. Back during the CRM3/4 days there was Stunnware. CRM2011 introduced capability to export the FetchXml directly from the Advanced Find. In CRM 2013/2015 you have four tools, to write and export the FetchXml.<br />
<ol style="text-align: left;">
<li>FetchXml Tester (comes with XRMToolBox)</li>
<li><a href="https://fxb.codeplex.com/" target="_blank">FetchXml Builder</a> </li>
<li><a href="https://ft3.codeplex.com/" target="_blank">Fetch Tester 3000</a></li>
<li><a href="https://chrome.google.com/webstore/detail/sonoma-partners-dynamics/eokikgaenlfgcpoifejlhaalmpeihfom" target="_blank">CRM DevTools</a> (Chrome only)</li>
</ol>
The fetchxml I build, is used mostly in a plugin or workflow assembly, but there are times when I want to store the fetchxml in custom entity, and use it a part of scheduled workflow logic. This also needs to be flexible, as I may need to change the fetchxml, without needing to rebuild any assemblies. The obvious and most straight forward way to do this would be to have a textarea field in the form, and copy-paste the fetchxml that was generated from one of this tools, or from the advanced find.<br />
<br />
What if there is an better, albeit <u><b>unsupported </b></u>way? You can embed the advanced find on the entity form that needs to store the fetchxml, and get the fetchxml from the advanced find, when the user saves the record.<br />
<br />
<u><b>Step 1</b></u>:<br />
You need two controls: a text area to store the fetchxml and an IFrame that will display the advanced find. The target of the IFrame is "about: blank". We will set the correct URL using Javascript. I have added the IFrame to a seperate tab, and the default state of this tab is collapsed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdCM3pfpmY4RvUyrALN4Ef8mrxB4hGIg8eT4_HQkwkT3molldtKfmPcAlzPFeGAFQPi6sBi7lBTWF6tzAjUAL2ZT7QzDzjFaXe5O55DBhmHmvpK6l6ERI3Q7y5CBo72R699WxIZNNXw2Y/s1600/Form1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdCM3pfpmY4RvUyrALN4Ef8mrxB4hGIg8eT4_HQkwkT3molldtKfmPcAlzPFeGAFQPi6sBi7lBTWF6tzAjUAL2ZT7QzDzjFaXe5O55DBhmHmvpK6l6ERI3Q7y5CBo72R699WxIZNNXw2Y/s1600/Form1.png" height="195" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXfxFyJg50gADFbq8fcNw0ULNyZPECqeX_rvS5bsx4CI_Dn3dBcX5XHeNgVjc_gm-AA_2tDuVQfVc9c9niVqQwLBO3GsFThh3h_qQf4OGL05ko7gY0kcvBu7ZF9Nmv4KV8OBhr5wmiz3g/s1600/Form2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXfxFyJg50gADFbq8fcNw0ULNyZPECqeX_rvS5bsx4CI_Dn3dBcX5XHeNgVjc_gm-AA_2tDuVQfVc9c9niVqQwLBO3GsFThh3h_qQf4OGL05ko7gY0kcvBu7ZF9Nmv4KV8OBhr5wmiz3g/s1600/Form2.png" height="216" width="640" /></a></div>
<br />
<u><b>Step 2</b></u>:<br />
Add the script below as a Javascript webresource and hookup the onSave and onLoad functions to the form save and form load respectively. The id of my IFrame is <i>IFrame_Advanced</i> and the fetchxml is stored in textarea <i>ryr_fetchxml</i>.<br />
<br />
<pre class="prettyprint">var RYR = window.RYR || {};
RYR.onLoad = function(){
Xrm.Page.getControl('IFRAME_AdvancedFind').setSrc(Xrm.Page.context.getClientUrl()+'/advancedfind/advfind.aspx?pagemode=iframe&navbar=off&cmdbar=false');
};
RYR.onSave = function(){
var advancedFindFrame = document.getElementById('IFRAME_AdvancedFind').contentWindow;
advancedFindFrame.ExecuteQuery();
advancedFindFrame.ShowQuery();
Xrm.Page.getAttribute('ryr_fetchxml').setValue(advancedFindFrame.document.getElementById('FetchXml').value);
};
window.RYR = RYR;
</pre>
<br />
Here is how it looks.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNVKXLSm3rYtgt4gVvQyB40qi3429o_t5Hi3r9Gr2M-Z-VJ3G0tE_CSqptiB-QOI1WPUHhWUqEQ9hgrXqtpXFZLCZ2FkyrT4_Tjnnkaa_ZVddO_wm-6u2NVj3A8kKI_14Kp6DXI-SSNNY/s1600/Form3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNVKXLSm3rYtgt4gVvQyB40qi3429o_t5Hi3r9Gr2M-Z-VJ3G0tE_CSqptiB-QOI1WPUHhWUqEQ9hgrXqtpXFZLCZ2FkyrT4_Tjnnkaa_ZVddO_wm-6u2NVj3A8kKI_14Kp6DXI-SSNNY/s1600/Form3.png" height="206" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLuWg8iT4kn9lhtJhwdYbJ4SLiCbhzRDX7vUyebMa51HmYZ_FOaqfFvcRUOd-QBN_pzeUOxGQNiFDycKH20xCDhx4QZyfLeucAyn_KllhLqdsZqxL5wBumn2bZvPXgp6J-l0LsSxXLcv0/s1600/Form4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
The trick is to call <i>ShowQuery </i>straight after <i>ExecuteQuery</i>, so that div with id FetchXml contains the correct value. If we don't call the <i>ExecuteQuery</i>, the value of <i>FetchXml </i>won't be updated when the advanced find is modified by the user.<br />
<br />
Once again, this technique is <u><b>unsupported</b></u>, so use it at your own risk. I have tested this in Firefox 34 and CRM 2013 6.1.0.581.<br />
<br />
<u><b>UPDATE (24/12/14):</b></u> There was an issue with the initial script, as it was only working if the organisation was a default one. The initial script split the screen horizontally, if the IFrame url was correctly set using <i>getClientUrl</i>. The updated script fixes this issue. Based on my testing, this is working in Firefox 34, Chrome 39.0.2171.95 and IE 11(in IE9 mode only). One more thing to note -> If the tab with the Advanced Find IFrame doesn't started out collapsed, the Ribbon Interface of the Advanced Find shows up on the form.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-10751120529165968522014-12-08T21:18:00.000+11:002014-12-08T21:18:37.841+11:00Quicktip: Install .net 4.5.2 before developing for CRM2015<div dir="ltr" style="text-align: left;" trbidi="on">
Before you start developing console application, workflow or plugin for CRM2015 the first step is to install .net 4.5.2 as this is required by CRM2015. I was working on a simple console application using CRM2015 assemblies and I encountered a weird error. I ran "<i>Install-Package Microsoft.CrmSdk.XrmTooling.CoreAssembly</i>" from the PM console without any issue. But when you try to build the application I got these compilation errors.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkxwEKTnElTNXoCpZLWex8IGu1Iw3DggLuwCb5nZdvMUyNeVrN6DmCeHitqJwZVrJf9EfUsgRh1GuyalUzOGFOuGSImc1MHdUelAhpxEl1Mc9aG8l0-f8z0ycXoGsbF6sxUUxgYJYq7pE/s1600/Errors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkxwEKTnElTNXoCpZLWex8IGu1Iw3DggLuwCb5nZdvMUyNeVrN6DmCeHitqJwZVrJf9EfUsgRh1GuyalUzOGFOuGSImc1MHdUelAhpxEl1Mc9aG8l0-f8z0ycXoGsbF6sxUUxgYJYq7pE/s1600/Errors.png" height="104" width="640" /></a></div>
<br />
The root cause of these errors is because the project is not targetting .net 4.5.2. Download .net 4.5.2 from <a href="http://www.microsoft.com/en-us/download/details.aspx?id=42637" target="_blank">http://www.microsoft.com/en-us/download/details.aspx?id=42637</a> and update the project target framework to .net 4.5.2. This time the build process succeeds. I was quite surprised that nuget did not prevent me from using the package in the project, even though I didn't have a the prerequisite framework version.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-40207323258193572232014-12-07T14:37:00.001+11:002014-12-07T14:37:25.485+11:00Calculated Fields in CRM 2015<div dir="ltr" style="text-align: left;" trbidi="on">
Calculated fields are new to CRM 2015. Business Rules now also have a new Entity Level scope option. When it comes to simple decimal operations you can use either Business Rules at Entity Level scope or calculated fields. Obviously calculated fields, are much more powerful than business rules. There is one issue I experienced with business rules at entity level. The division operator currently does not seem to work properly.<br />
<br />
This the business rule to perform the division.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbOd2nmHFux3a31Xu0OJ0ff73XXPQWCGA0Id80EfgUccM71iqkfbxj_wJf7RmpaalYJTiGekBXdJdp8yKQd5_YwDSpwFEFMM40S3ajEfJCWN58lp1RhY3RDQK7231fJAljXnQpilXOFFw/s1600/Division+Rule.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbOd2nmHFux3a31Xu0OJ0ff73XXPQWCGA0Id80EfgUccM71iqkfbxj_wJf7RmpaalYJTiGekBXdJdp8yKQd5_YwDSpwFEFMM40S3ajEfJCWN58lp1RhY3RDQK7231fJAljXnQpilXOFFw/s1600/Division+Rule.png" height="268" width="640" /></a></div>
<br />
When you save the record an error is displayed.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELm5KXwrk-YvIgEACWK-njZ4gyjq7VqrAwvL3ErR2Xnw-MQNl9GRwxR-HH3YTictbD0YmQ84hyphenhypheny76mDlKx2UqAPLXI8wNqAntRxk2EMVZ7HAwhvPf8ZT5eKKUpC0pQ46_eu2a8InIR5s/s1600/Division+Error.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELm5KXwrk-YvIgEACWK-njZ4gyjq7VqrAwvL3ErR2Xnw-MQNl9GRwxR-HH3YTictbD0YmQ84hyphenhypheny76mDlKx2UqAPLXI8wNqAntRxk2EMVZ7HAwhvPf8ZT5eKKUpC0pQ46_eu2a8InIR5s/s1600/Division+Error.png" height="222" width="640" /></a></div>
<br />
This is the actual error<br />
<br />
<pre class="prettyprint">Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Expression operator not supported for specified type.Detail:
<OrganizationServiceFault xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/xrm/2011/Contracts">
<ErrorCode>-2147220891</ErrorCode>
<ErrorDetails xmlns:d2p1="http://schemas.datacontract.org/2004/07/System.Collections.Generic">
<KeyValuePairOfstringanyType>
<d2p1:key>OperationStatus</d2p1:key>
<d2p1:value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">0</d2p1:value>
</KeyValuePairOfstringanyType>
<KeyValuePairOfstringanyType>
<d2p1:key>SubErrorCode</d2p1:key>
<d2p1:value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">-2146233088</d2p1:value>
</KeyValuePairOfstringanyType>
</ErrorDetails>
<Message>Expression operator not supported for specified type.</Message>
<Timestamp>2014-12-06T22:54:07.9005933Z</Timestamp>
<InnerFault i:nil="true" />
<TraceText>
[Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.SyncWorkflowExecutionPlugin]
[c3877360-9a7d-e411-80cf-e83935c2f340: ]
Starting sync workflow 'Decimal Formula', Id: bc877360-9a7d-e411-80cf-e83935c2f340
Entering ConditionStep1_step:
Sync workflow 'Decimal Formula' terminated with error 'Expression operator not supported for specified type.'
</TraceText>
</OrganizationServiceFault>
</pre>
<br />
The calculated field that performs the division works without any issue.<br />
<br />
Interesting behaviours that I encountered below.<br />
<br />
<b>Scenario 1</b>: Calculated field to divide two integers and the result of the operation is float e.g. : 5 / 2<br />
<br />
<b>Result</b>: The result is rounded up to the closest int.<br />
<br />
<img alt="" height="54" src="data:image/png;base64,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" width="640" /><br />
<b> </b><br />
<b>Scenario 2</b>: Calculated field - Divide by zero<br />
<br />
<b>Result</b>: No divide by zero exception. The result is blank.<br />
<br />
<img alt="" height="58" src="data:image/png;base64,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" width="640" /><br />
<br />
<b>Scenario 3</b>: Calculated field of type text, with calculation using decimal fields.<br />
<br />
<b>Result</b>: No error. Result of the operation is can be assigned to the string field.<br />
<br />
<img alt="" height="101" src="data:image/png;base64,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" width="640" /><br />
<br />
<b>Conclusion</b>: If it can be done using calculated fields, do it that way, instead of Entity scope business rules, as calculated fields offer much more flexibility and functionality.</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-979287395599124602014-11-15T14:02:00.002+11:002014-11-15T16:02:48.344+11:00Tip: Using Nuget to reference CRM2013 assemblies<div dir="ltr" style="text-align: left;" trbidi="on">
If you are a <strike>lazy</strike> productive developer, you probably are already using nuget to add CRM SDK assemblies to your project. I generally used to add the CRM2013 SDK using the nuget GUI, but recently I had to change this behaviour. The reason being CRM 2015 SDK is also available in nuget repo, and it uses the same package name that was previously used to CRM2013 SDK. These are the packages, that now show up with a Microsoft Dynamics CRM 2015 prefix, that were previously used for CRM 2013.<br />
<ol style="text-align: left;">
<li>Microsoft.CrmSdk.CoreAssemblies</li>
<li>Microsoft.CrmSdk.Deployment</li>
<li>Microsoft.CrmSdk.Outlook</li>
<li>Microsoft.CrmSdk.Workflow </li>
</ol>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeyeZUVGbLxpHW_x9Nn7TfokvBNosrybXTQuYKzCYDHg4CZK4X18UChrBahL1PV0BeOkrpHT1YbjaNTV0iZIxaP7EdYwokYa01BdMdbevP-Rp_HzGFwcK-yWUyRU00zVd9qbg7VMb_aF4/s1600/NugetGUI.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeyeZUVGbLxpHW_x9Nn7TfokvBNosrybXTQuYKzCYDHg4CZK4X18UChrBahL1PV0BeOkrpHT1YbjaNTV0iZIxaP7EdYwokYa01BdMdbevP-Rp_HzGFwcK-yWUyRU00zVd9qbg7VMb_aF4/s1600/NugetGUI.png" height="510" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
The resolution for this issue, is to use the Package Manager Console, for installing the CRM 2013 SDKs. To open Package Manager console, use View -> Other Windows -> Package Manager Console.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHWravXZBoVP0Vs1-Pn80c0hQnSvT0mBd8hfuV2189RHlnr2MeFK1t9JfDc5rHoXw_7gPiOU5DGZ69wOBOU9rL_hmgFUkZG2COlRc_jntYJ-yulMPi83wiOZAe-9-NEkpXM-Yhjs4hnas/s1600/PMmenu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHWravXZBoVP0Vs1-Pn80c0hQnSvT0mBd8hfuV2189RHlnr2MeFK1t9JfDc5rHoXw_7gPiOU5DGZ69wOBOU9rL_hmgFUkZG2COlRc_jntYJ-yulMPi83wiOZAe-9-NEkpXM-Yhjs4hnas/s1600/PMmenu.png" height="506" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
Then type the required package name along with the version number to add the references to your project. Version Number for CRM 2013 SDK SP1 UR1 is 6.1.1.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP-maUK3N3lYbtkvk5m6dgQcnIoFAtUQbf-tsokXZf3exR5tpP95CtsoP2YnouLy5FaWY4_0_IFjLOI72J7v6OmmwN-nioPlLX9-hGbtL0QeI7iQTtQ7G5le6HU0qDzrXUA0bJCD5CE6o/s1600/PMconsole.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgP-maUK3N3lYbtkvk5m6dgQcnIoFAtUQbf-tsokXZf3exR5tpP95CtsoP2YnouLy5FaWY4_0_IFjLOI72J7v6OmmwN-nioPlLX9-hGbtL0QeI7iQTtQ7G5le6HU0qDzrXUA0bJCD5CE6o/s1600/PMconsole.png" height="208" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br /></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-54023893552965166262014-11-13T20:53:00.002+11:002014-11-14T08:38:59.723+11:00Bug in Plugin Registration Tool for CRM2013 - 6.1<div dir="ltr" style="text-align: left;" trbidi="on">
Today I wasted around half-an-hour trying to troubleshoot why Plugin Registration tool was not recognising my custom workflow activity. When I tried to register the assembly, the tool would not display any custom activity.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZOhxskncMmP2O7WAGefGj1U3-R6A_XJifUTvPaonVdVKk-1C0wnzNX-fj1TqhViex-NoW778rWrPLM_L5BqrMc1bXScWYj3vVM1n-QAJ_mpPC2dJBJ1dniGtGDC4Wkg86rAl_45nRlLE/s1600/2014-11-13+15_21_27-PluginRegistrationView.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZOhxskncMmP2O7WAGefGj1U3-R6A_XJifUTvPaonVdVKk-1C0wnzNX-fj1TqhViex-NoW778rWrPLM_L5BqrMc1bXScWYj3vVM1n-QAJ_mpPC2dJBJ1dniGtGDC4Wkg86rAl_45nRlLE/s640/2014-11-13+15_21_27-PluginRegistrationView.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidUsTudTMlfdfJAiSHzQFWJrkY28bDRQ1LSHOvRGrsZHZtBSjWGUnv7LQUjA3tz-U1bsIbpA6oV2jVjMFkmsWhpXkyMKs5T2SHEK3KeEHXCRBqa4KQVZOphfqOYe-yEJJ4MpXvvHfbBzo/s1600/2014-11-13+15_21_27-PluginRegistrationView.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
The version I was using is 6.1.1143.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitMnFIf37tb7zCf3F3y3H_pGhgYv3Lh8MsOqzqnbm6VAHyLe-TwPdYsyyEvKIFNtKWSnaC4ldz9JM5mx-zDpe5NNroVPDbKxAL9hw5K_EJQgsC1lKpMqBJfy478ekNtUXD1v4U-VdgSts/s1600/2014-11-13+15_21_00-Plugin+Registration+Tool.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitMnFIf37tb7zCf3F3y3H_pGhgYv3Lh8MsOqzqnbm6VAHyLe-TwPdYsyyEvKIFNtKWSnaC4ldz9JM5mx-zDpe5NNroVPDbKxAL9hw5K_EJQgsC1lKpMqBJfy478ekNtUXD1v4U-VdgSts/s640/2014-11-13+15_21_00-Plugin+Registration+Tool.png" width="640" /> </a></div>
<div class="separator" style="clear: both; text-align: left;">
I checked the obvious things</div>
<ol style="text-align: left;">
<li>Activity class is public </li>
<li>Assembly is signed</li>
<li>Workflow class extends CodeActivity</li>
<li>Built using .net 4.5</li>
</ol>
Since I could not figure out the reason behind this issue, I tried this in the CRM2015 SDK Plugin Registration tool (v 6.1.0.519).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWkWfgeilT5Hx6EDsVQ4w8rMOc7cqLCXTWHp9QRSDL5PGn74cFD0m2H9aD2ahEEAhB2CvOwByBQIyhsVCR_pxVLLula5Y9-a58BoSeQ1ioib629lTHb2vAXNq9UhwtRGC9T6JcDknFA9s/s1600/2014-11-13+15_22_14-Plugin+Registration+Tool2015.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWkWfgeilT5Hx6EDsVQ4w8rMOc7cqLCXTWHp9QRSDL5PGn74cFD0m2H9aD2ahEEAhB2CvOwByBQIyhsVCR_pxVLLula5Y9-a58BoSeQ1ioib629lTHb2vAXNq9UhwtRGC9T6JcDknFA9s/s640/2014-11-13+15_22_14-Plugin+Registration+Tool2015.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj01MlbGzgcxsUW-q-NLSA2goS0PYFn3BIRIAOPe3YdV6K7Tk9a_m-CFM_yxt5jp7lJh9b9qxo0pAFY-8-hiis8vk3XS-ZiXYwLDLwMnmND-fyTEwXOrj8RIK8YSDv2srBTTDQ__ZvE18w/s1600/2014-11-13+15_22_36-PluginRegistrationView2015.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj01MlbGzgcxsUW-q-NLSA2goS0PYFn3BIRIAOPe3YdV6K7Tk9a_m-CFM_yxt5jp7lJh9b9qxo0pAFY-8-hiis8vk3XS-ZiXYwLDLwMnmND-fyTEwXOrj8RIK8YSDv2srBTTDQ__ZvE18w/s640/2014-11-13+15_22_36-PluginRegistrationView2015.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
I was able to register the workflow assembly without any issues. The old plugin registration tool worked without any issues as well. So, currently it seems, it is better to avoid the new plugin registration tool in CRM2013 SDK.</div>
<br />
<br /></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-8730030160603492792014-10-22T11:24:00.002+11:002014-10-22T12:37:14.942+11:00Executing Quick Find from Console Application : Redux<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
If you have been following my blog, you might remember this (<a href="http://nycrmdev.blogspot.com.au/2014/05/executing-quickfind-using-crm-sdk.html" target="_blank">http://nycrmdev.blogspot.com.au/2014/05/executing-quickfind-using-crm-sdk.html</a>) post about executing a quick find query from the console. It was using an undocumented message, and hence it is unsupported. I had a crack at this problem one more time, this time using Actions.<br />
<br />
In order to return the quick find results, the custom action need to have a EntityCollection output parameter. I posted this (<a href="https://community.dynamics.com/crm/f/117/t/128534.aspx" target="_blank">https://community.dynamics.com/crm/f/117/t/128534.aspx</a>) question in CRM forums sometime back and didn't get any response.<br />
<br />
<br />
This is not production ready code and just demonstrates how this can be done. If you would rather read the code, instead of this post please find the download link in the very bottom.<br />
<br />
<u><b>Requirements</b></u>:<br />
For the search - should be able to specify: <br />
1.) Entity name<br />
2.) Search term<br />
3.) Page number<br />
4.) Number of records to be returned<br />
<br />
<u><b>Step 1</b></u>: Create a custom action<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyiGWbezVeWRxXHnUIzfEz74gE0s9MOFBfhBpaobeBru08HN4rdGRgRAK1zetv7kvFFglMwhErLFJA5cnn04miPGV_E8WlYbpxzCnupCreH_MuKjyVgu_07IZfYwFh8fUGZbWW9UpucGg/s1600/ActionDefinition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyiGWbezVeWRxXHnUIzfEz74gE0s9MOFBfhBpaobeBru08HN4rdGRgRAK1zetv7kvFFglMwhErLFJA5cnn04miPGV_E8WlYbpxzCnupCreH_MuKjyVgu_07IZfYwFh8fUGZbWW9UpucGg/s1600/ActionDefinition.png" height="266" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
The body of the action is empty and doesn't contain any logic. The actual quickfind will be performed by a plugin registered post-operation of this action.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<u><b>Step 2</b></u>: Create the plugin</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="prettyprint">using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Linq;
using System.Xml.Linq;
using Contract = System.Diagnostics.Contracts.Contract;
namespace QuickFindAction.Plugins
{
public class QuickFindPlugin : IPlugin
{
internal IOrganizationService OrganizationService
{
get;
private set;
}
internal IPluginExecutionContext PluginExecutionContext
{
get;
private set;
}
internal ITracingService TracingService
{
get;
private set;
}
public void Execute(IServiceProvider serviceProvider)
{
Contract.Assert(serviceProvider != null, "serviceProvider is null");
PluginExecutionContext =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
TracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
Contract.Assert(TracingService != null, "TracingService is null");
try
{
var factory =
(IOrganizationServiceFactory) serviceProvider.GetService(typeof (IOrganizationServiceFactory));
OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId);
Contract.Assert(PluginExecutionContext.InputParameters.Contains("SearchTextInput"), "No SearchTextInput property");
Contract.Assert(
!string.IsNullOrEmpty(PluginExecutionContext.InputParameters["SearchTextInput"].ToString()), "SearchTextInput is null or empty");
Contract.Assert(PluginExecutionContext.InputParameters.Contains("EntityNameInput"), "No EntityNameInput property");
string searchText = PluginExecutionContext.InputParameters["SearchTextInput"].ToString(),
searchEntity = PluginExecutionContext.InputParameters["EntityNameInput"].ToString();
var savedViewQuery = string.Format(
@"<fetch version=""1.0"" output-format=""xml-platform"" mapping=""logical"" distinct=""false"">
<entity name=""savedquery"">
<attribute name=""fetchxml"" />
<filter type=""and"">
<condition attribute=""statecode"" operator=""eq"" value=""0"" />
<condition attribute=""isquickfindquery"" operator=""eq"" value=""1"" />
<condition attribute=""isdefault"" operator=""eq"" value=""1"" />
<condition attribute=""name"" operator=""like"" value=""%{0}%"" />
</filter>
</entity>
</fetch>", searchEntity);
var quickFindFetchXml =
OrganizationService.RetrieveMultiple(new FetchExpression(savedViewQuery)).Entities[0].GetAttributeValue<string>("fetchxml");
TracingService.Trace("FetchXml read from SavedView");
var entityFetchXml = XElement.Parse(string.Format(quickFindFetchXml, string.Format("%{0}%", searchText)));
if (PluginExecutionContext.InputParameters["Page"] != null)
{
entityFetchXml.SetAttributeValue("page", PluginExecutionContext.InputParameters["Page"]);
}
if (PluginExecutionContext.InputParameters["Count"] != null)
{
entityFetchXml.SetAttributeValue("count", PluginExecutionContext.InputParameters["Count"]);
}
entityFetchXml.Elements().Elements("filter").Elements().ToList().ForEach(x => {
if (
x.Attribute(
"attribute")
.Value
.EndsWith("id"))
{
x.SetAttributeValue("attribute",x.Attribute("attribute").Value+"name");
} });
PluginExecutionContext.OutputParameters["FetchXml"] = entityFetchXml.ToString();
var results = OrganizationService.RetrieveMultiple(new FetchExpression(entityFetchXml.ToString()));
PluginExecutionContext.OutputParameters["SearchResultsOutput"] = new EntityCollection(results.Entities.ToList());
}
catch (Exception e)
{
TracingService.Trace(e.StackTrace);
PluginExecutionContext.OutputParameters["Exception"] = e.StackTrace;
throw;
}
}
}
}
</pre>
</div>
<br />
<u><b>Step 3</b></u>: Register the plugin<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFv33-96IurtrxQIL893_LEPR8wJGDAV074RI-ter6zEUNAm-kQ2Q1FuiEGWiA4_7HisG1ygBHb0sM6ihvykbbPFQn-gNA-ntR-kIhi-Y5fYExRsByussvTtTO64xebnG3X9iU1zCHGtA/s1600/PluginDefinition1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFv33-96IurtrxQIL893_LEPR8wJGDAV074RI-ter6zEUNAm-kQ2Q1FuiEGWiA4_7HisG1ygBHb0sM6ihvykbbPFQn-gNA-ntR-kIhi-Y5fYExRsByussvTtTO64xebnG3X9iU1zCHGtA/s1600/PluginDefinition1.png" height="566" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrqIYspAAFo45axESV4iS0R-ewFKNrNSlvb2SCVcQU_36fNYQMDddhZew1RtfmzunS2jph_PWprO38LxGC4LbCkBTY4iu-9hgqYN8fEtnJg1P9Qn8KwROXPm3DrZ1y8L8ktD3QcMFORAw/s1600/StepDefinition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrqIYspAAFo45axESV4iS0R-ewFKNrNSlvb2SCVcQU_36fNYQMDddhZew1RtfmzunS2jph_PWprO38LxGC4LbCkBTY4iu-9hgqYN8fEtnJg1P9Qn8KwROXPm3DrZ1y8L8ktD3QcMFORAw/s1600/StepDefinition.png" height="626" width="640" /></a></div>
<br />
<u><b>Step 4</b></u>: Create the Console Application<br />
<pre class="prettyprint">using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Tooling.Connector;
namespace ActionsTester
{
class Program
{
static void Main(string[] args)
{
try
{
var executeQuickFindRequest = new OrganizationRequest("ryr_Search");
executeQuickFindRequest["SearchTextInput"] = "sus";
executeQuickFindRequest["EntityNameInput"] = "contact";
executeQuickFindRequest["Page"] = 1;
//executeQuickFindRequest["Count"] = 1;
var crmSvc =
new CrmServiceClient(new NetworkCredential("administrator", "p@ssw0rd1", "CRM"),
AuthenticationType.AD, "crm1", "80", "Contoso");
if (crmSvc.IsReady)
{
crmSvc.OrganizationServiceProxy.Execute(executeQuickFindRequest);
OrganizationResponse response = crmSvc.OrganizationServiceProxy.Execute(executeQuickFindRequest);
if (response.Results.Contains("Exception") && response.Results["Exception"] != null)
{
Console.WriteLine(response.Results["Exception"]);
Console.WriteLine(response.Results["FetchXml"]);
return;
}
if (response.Results["SearchResultsOutput"] != null)
{
Console.WriteLine(response.Results["FetchXml"]);
var results = (EntityCollection) response.Results["SearchResultsOutput"];
foreach (var record in results.Entities)
{
record.Attributes.ToList().ForEach(x=> Console.WriteLine("{0}={1}",x.Key,Unwrap(x.Value)));
Console.WriteLine();
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
}
private static object Unwrap(object attributeValue)
{
var unwrappedValue = attributeValue;
if (attributeValue is EntityReference)
{
unwrappedValue = ((EntityReference) attributeValue).Name;
}
else
if (attributeValue is OptionSetValue)
{
unwrappedValue = ((OptionSetValue)attributeValue).Value;
}
else
if (attributeValue is Money)
{
unwrappedValue = ((Money)attributeValue).Value;
}
return unwrappedValue;
}
}
}
</pre>
<br />
<u><b>Output</b></u>:<br />
The search term is "sus" and the entity is contact <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG8g6tI7mbUUgb7PZN8Klit5g0KWXUXIAQnLGk1piNGy8Da8v-PvyhwkM3K2jVk6fgyGbNf5gNEbMaVisrCOZk6kcWds6kQyslxYZHtmUrsCU17KttDsYFyEAu3KcZAMSsDr6ZU8QtBSM/s1600/output.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG8g6tI7mbUUgb7PZN8Klit5g0KWXUXIAQnLGk1piNGy8Da8v-PvyhwkM3K2jVk6fgyGbNf5gNEbMaVisrCOZk6kcWds6kQyslxYZHtmUrsCU17KttDsYFyEAu3KcZAMSsDr6ZU8QtBSM/s1600/output.png" height="400" width="353" /></a></div>
<br />
<u><b>Limitations</b></u>:<br />
1.) Search term is field type agnostic (exception of a lame entity reference mapping). So if a Optionset is in the quickfind query, the search term won't work properly<br />
2.) Assumption is made that the quick find view name has the entity name. So if entity name is contact and the quick find view doesn't have the word contact this won't work properly.<br />
3.) Assumption is made that schema name for lookups end with id. <br />
<br />
<u><b>Problems Faced</b></u>:<br />
I was initially using strongly typed entities with a generated service context in the plugin, but had some serialisation exceptions along the way and decided to switch to query approach to get the application working. The exception was<br />
<br />
<pre class="prettyprint">>System.Runtime.Serialization.SerializationException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #59D91113:
System.Runtime.Serialization.SerializationException: Element 'http://schemas.microsoft.com/xrm/2011/Contracts:Entity' contains data from a type that maps to the name 'Contoso.EarlyBound.Generated:Contact'.
The deserializer has no knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName method on your DataContractResolver to return a non-null value for name 'Contact'
and namespace 'Contoso.EarlyBound.Generated'.
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
> at ReadArrayOfEntityFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString , XmlDictionaryString , CollectionDataContract )
> at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
> at ReadEntityCollectionFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
> at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
> at ReadKeyValuePairOfstringanyTypeFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )
> at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)
> at ReadParameterCollectionFromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString , XmlDictionaryString , CollectionDataContract )
> at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)
> at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
> at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
> at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
> at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)
> at Microsoft.Crm.Sandbox.SandboxUtility.DeserializeDataContract[T](Byte[] serializedDataContract, Assembly proxyTypesAssembly)
> at Microsoft.Crm.Sandbox.SandboxExecutionContext.Merge(IExecutionContext originalContext)
> at Microsoft.Crm.Sandbox.SandboxCodeUnit.Execute(IExecutionContext context)
</pre>
<br />
<br />
<u><b>Observation</b></u>:<br />
1.) I was surprised to see <i>address1_composite</i> on the result set even though I did not mention it in the search find query. Running the exact same query in XrmToolBox FetchXml Tester doesn't return <i>address1_composite</i> field.<br />
2.) count=0 on a fetchxml somehow works and returns records if matches are found. <br />
<br />
<u><b>Improvements that can be made</b></u>:<br />
1.) Parse the attributes in quickfind fetchxml and retrieve the types of these attributes, so that the search query can be correctly mapped.<br />
2.) Use <a href="http://pfexrmcore.codeplex.com/" target="_blank">PFE Core Library</a> on the retrieve part<br />
3.) Add additional types to the unwrapping code in console application (currently unwraps only entityreference, optionsetvalue and money).<br />
<br />
<u><b>Conclusion</b></u>:<br />
Actions are AWESOME. I can write a logic once and can call this from console application, workflow or javascript. Previously you would have to encapsulate this logic on a webservice, to get this kind of extensibility.<br />
<br />
<u><b>Code</b></u>: <a href="http://1drv.ms/1w5GJ2b" target="_blank">http://1drv.ms/1w5GJ2b</a></div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0tag:blogger.com,1999:blog-5070296464471386188.post-19008254298116358552014-10-17T12:55:00.003+11:002014-10-17T15:54:57.001+11:00Copy Record Id of a row from Advanced Find<div dir="ltr" style="text-align: left;" trbidi="on">
I have recently started using bookmarklets to improve productivity during CRM Development. There are plenty of bookmarklets that I use, and of these I quite frequently use these:<br />
<ol style="text-align: left;">
<li>Copy Record Id (<a href="http://blog.sonomapartners.com/2014/01/crm-2013-javascript-bookmark-series-part-1.html" target="_blank">http://blog.sonomapartners.com/2014/01/crm-2013-javascript-bookmark-series-part-1.html</a>)</li>
<li>Open Advanced Find (<span id="goog_1765620605"></span><a href="https://www.blogger.com/"></a><span id="goog_1765620606"></span><a href="http://www.magnetismsolutions.com.au/blog/paulnieuwelaar/2014/07/24/crm-2013-open-advanced-find-from-anywhere-with-bookmarklet" target="_blank">http://www.magnetismsolutions.com.au/blog/paulnieuwelaar/2014/07/24/crm-2013-open-advanced-find-from-anywhere-with-bookmarklet</a>)</li>
<li>Open Default Solution (<a href="http://www.magnetismsolutions.com.au/blog/paulnieuwelaar/2014/07/27/customize-and-publish-from-crm-2013-forms-with-bookmarklets" target="_blank">http://www.magnetismsolutions.com.au/blog/paulnieuwelaar/2014/07/27/customize-and-publish-from-crm-2013-forms-with-bookmarklets</a>)</li>
</ol>
<a href="https://www.blogger.com/blogger.g?blogID=5070296464471386188" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a>Inorder to use the Copy Record Id bookmarket you'll have to be in the record form. I found this inconvinient when I was viewing the results from Advanced Find. You can bookmarklet the below script to quickly extract the primary key of the selected row in the Advanced Find resultset.<br />
<br />
<pre class="prettyprint">javascript:var contentFrame=document.getElementById('contentIFrame0'),isError=false;if(contentFrame){var resultFrame=contentFrame.contentWindow.document.getElementById('resultFrame');if(resultFrame&&resultFrame.contentWindow){var selectedRow=resultFrame.contentWindow.document.querySelector('.ms-crm-List-SelectedRow');if(selectedRow){window.prompt('Copy to clipboard: Ctrl+C, Enter',selectedRow.getAttribute('oid'));}
else{alert('Please select a row to get the id');}}else{isError=true;}}else{isError=true;}
if(isError){alert('Unable to locate result frame to extract rowid');}
void 0;
</pre>
<br />
Here is the how it looks when you run the code on a row in the advanced find result.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2a95lab0MKwN4lfx7kOiFfEVpoSqKlj6KFc0TJnXWglFuw58AUZIAy9kkULPdE-qTVh2Vpe9NwZmj6pYmFDR1o3CkjRHmO6DUwFUaAql7WWDqVTJw7gGOV5LXIHSH7bo1mEB8vbT2uZs/s1600/recordid.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2a95lab0MKwN4lfx7kOiFfEVpoSqKlj6KFc0TJnXWglFuw58AUZIAy9kkULPdE-qTVh2Vpe9NwZmj6pYmFDR1o3CkjRHmO6DUwFUaAql7WWDqVTJw7gGOV5LXIHSH7bo1mEB8vbT2uZs/s1600/recordid.png" height="257" width="640" /></a></div>
<br />
<br />
I have tested this in the latest version of Firefox (33) and Chrome (38) and it works.
</div>
RajYRamanhttp://www.blogger.com/profile/13016849429661418188noreply@blogger.com0