User not found error

Word of warning: This change is unsupported as it involves editing the CRM database directly. Use it at your own risk.

I encountered a weird error in CRM, that basically said that the user cannot be found. When I checked the event log, this appeared to be the underlying exception:

Exception type: CrmException
Exception message: No Microsoft Dynamics CRM user exists with the specified domain name and user ID
at Microsoft.Crm.Authentication.Claims.AuthenticationProvider.GetOrganizationId(ClaimsPrincipal principal)
at Microsoft.Crm.Authentication.Claims.AuthenticationProvider.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationStep.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationPipeline.Authenticate(HttpApplication application)
at Microsoft.Crm.Authentication.AuthenticationEngine.Execute(Object sender, EventArgs e)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

But, the user was indeed there from before and all I did was reactivate a long dormant user. My initial suspicion was that this had something to do with AD. I ran the following query to check the SID of the user against the MSCRM_CONFIG database:

select c.FriendlyName,b.FullName,d.AuthInfo,b.DomainName
from SystemUserOrganizations a
inner join [ORG_MSCRM].dbo.SystemUser b on a.CrmUserId=b.SystemUserId
inner join Organization c on c.Id=a.OrganizationId
inner join SystemUserAuthentication d on d.UserId=a.UserId
where b.DomainName='CONTOSO\powerm'

This gave me the SID of the user when the user was first created in CRM. I next ran this command in to get the current SID of the user:

wmic useraccount where name='powerm' get sid

The SID did not match to the one already in CRM, so I had to update it in the MSCRM_CONFIG database:

update d
set d.AuthInfo='W:[SID OUTPUT FROM THE DOS COMMAND PROMPT]'
from SystemUserOrganizations a
inner join [ORG_MSCRM].dbo.SystemUser b on a.CrmUserId=b.SystemUserId
inner join Organization c on c.Id=a.OrganizationId
inner join SystemUserAuthentication d on d.UserId=a.UserId
where b.DomainName='CONTOSO\powerm'

Once I updated this, the user was able to login with the same AD account.

Export to Excel using Dynamics 365 SDK

With the new Dynamics 365 release, a new message has been added that making exporting FetchXML results really simple. This message is not documented, hence is technically unsupported. With that word of warning, I will show you how to utilise this new message to export data from Dynamics 365 to an Excel file.

ExportToExcel message definition

Parameter Type
View EntityReference
FetchXml string
LayoutXml string
QueryApi string
QueryParameters InputArgumentCollection

Code

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;

namespace Experiments
{
    class Program
    {
        private static OrganizationService _orgService;
        static void Main(string[] args)
        {
            try
            {
                CrmConnection connection = CrmConnection.Parse(
                    ConfigurationManager.ConnectionStrings["CRMConnectionString"].ConnectionString);

                using (_orgService = new OrganizationService(connection))
                {
                    var exportToExcelRequest = new OrganizationRequest("ExportToExcel");
                    exportToExcelRequest.Parameters = new ParameterCollection();
                    //Has to be a savedquery aka "System View" or userquery aka "Saved View"
                    //The view has to exist, otherwise will error out
                    //Guid of the view has to be passed
                    exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object> ("View",
                        new EntityReference("userquery", new Guid("{0B915102-24A7-E611-8101-1458D05B1178}"))));
                    exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("FetchXml", @"
                    <fetch distinct='false' no-lock='false' mapping='logical' returntotalrecordcount='true'>
	                    <entity name='contact'>
		                    <attribute name='fullname' />
	                    </entity>
                    </fetch>"));
                    exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("LayoutXml", @"
                    <grid name='resultset' object='2' jump='fullname' select='1' icon='1' preview='1'>
	                    <row name='result' id='contactid'>
		                    <cell name='fullname' width='300' />
	                    </row>
                    </grid>"));
                    //need these params to keep org service happy
                    exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("QueryApi", ""));
                    exportToExcelRequest.Parameters.Add(new KeyValuePair<string, object>("QueryParameters",
                        new InputArgumentCollection()));
                    var exportToExcelResponse = _orgService.Execute(exportToExcelRequest);
                    if (exportToExcelResponse.Results.Any())
                    {
                        File.WriteAllBytes("Active Contacts.xlsx", exportToExcelResponse.Results["ExcelFile"] as byte[]);
                    }
                }
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                string message = ex.Message;
                throw;
            }
        }
    }
}

Closing Notes:

  1. “View” parameter can accept “userquery” or “savedquery”, but they have to exist i.e. you can’t pass empty Guid.
  2. The fetchxml and layoutxml can be different from what is in the “savedquery” or “userquery”. Hence, you can create a “Personal View” just so that you can use it in this message, but modify the fetchxml and layoutxml to whatever you want.
  3. The name of the tab in the Excel output file will be the name of the view specified in the “View” parameter
  4. This message can be executed from Javascript as well, but you will get a base64 string instead of a byte array in the response.

Please vote up my request on Connect (logged Feb 2015) -> https://connect.microsoft.com/site687/feedback/details/1127874/export-to-excel-sdk-message so that this message can be made available as an unbound WebAPI action.

Deploying a CRM2015 solution to CRM2013

There have been some great posts recently on how to deploy a CRM2011/CRM2013 solution to CRM2015.
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 https://support.microsoft.com/en-us/kb/2917899 if you are on a higher/lower rollup and modify the version number appropriately.In order to import the CRMOnline solution I had to
1. Extract the solution zip file

2. Change the first line of the solution.xml
from

&lt;ImportExportXml version="7.0.0000.5026" SolutionPackageVersion="7.0" languagecode="1033" generatedBy="CrmLive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;

to

&lt;ImportExportXml version="6.1.0001.0132" SolutionPackageVersion="6.1" languagecode="1033" generatedBy="CrmLive" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;

3.Delete <IsEnabledForMobileClient>0</IsEnabledForMobileClient> from every single webresource node in customizations.xml

4. Rezip the files

After performing these steps, I was able to import the solution into the CRM2013 environment. As with the other two posts, this is an unsupported method, so use it at your own risk.

Notes Control in CRM 2013 SP1

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.

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.

setTimeout("(function() { var t = document.querySelector('.tabLink.active'); if(t) { t.click(); } })();",2000);

This issue doesn’t seem to be happening in CRM2013 SP1 UR1 and CRM2015 and hence this (unsupported) fix is not applicable to these versions.

Using Advanced Find FetchXml capability in custom forms

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.

  1. FetchXml Tester (comes with XRMToolBox)
  2. FetchXml Builder
  3. Fetch Tester 3000
  4. CRM DevTools (Chrome only)

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.

What if there is an better, albeit unsupported 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.

Step 1:
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.

Step 2:
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 IFrame_Advanced and the fetchxml is stored in textarea ryr_fetchxml.

var RYR = window.RYR || {};

RYR.onLoad = function(){
  Xrm.Page.getControl('IFRAME_AdvancedFind').setSrc(Xrm.Page.context.getClientUrl()+'/advancedfind/advfind.aspx?pagemode=iframe&amp;navbar=off&amp;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;

Here is how it looks.

The trick is to call ShowQuery straight after ExecuteQuery, so that div with id FetchXml contains the correct value. If we don’t call the ExecuteQuery, the value of FetchXml won’t be updated when the advanced find is modified by the user.

Once again, this technique is unsupported, so use it at your own risk. I have tested this in Firefox 34 and CRM 2013 6.1.0.581.

UPDATE (24/12/14): 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 getClientUrl. 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.

Changing the default view of an inline lookup in CRM 2013

Dynamics CRM 2013 has done away with the ribbon interface, with the exception of a few forms. There are also some changes in the subgrid behavior. These are

1.) When you select a record in a subgrid ribbon menu no longer appears on top of the page
2.) Clicking the “+” icon above the subgrid, may display an inline lookup

I say “may” because it depends on the relationship. An inline lookup is only displayed when the parent entity field is NOT mandatory on the child record you are trying to create. When the inline lookup is displayed on a subgrid, there is no way to access this inline lookup control using CRM Client API.

There is however, an unsupported way to set the default view on an inline lookup. I am using Ribbon Workbench, by Scott Durow, as it makes the process much easier.

First notedown the name of the subgrid. In this example, I am trying to customise the contact subgrid on account. Note this down, as it is required in the later steps.


In this case, the subgrid is called accountContactsGrid. Next we have to get the GUID of the view we want to default to. There are two ways to do this: looking into the database or using Developer Tools. Open an account record, and try to add a contact to the subgrid. When the lookup selection popup appears, use Developer Tools to get the GUID of the required view. In this case, we want the GUID of Contacts: No Campaign Activities in Last 3 Months view. Note this down, as it also required in the script we will add later.



Open the solution with the contact entity in Ribbon Workbench. In this case I am trying to change the behavior of the contact subgrid. Ribbon Workbench displays the following subgrid menu for the contact entity.

Since this is a 1:M relationship and account relationship field is not mandatory on contact record, the first Add Existing button has to be customised. Right click on the first Add Existing button and click Customise Command.

The default command behavior is as below

The Mscrm.GridRibbonActions.addExistingFromSubGridStandard function is called with the entity typecode and the grid control as parameters. This has to be changed to call our custom function in a JavaScript webresource.

Create, upload and publish a new Javascript webresource with the code below. Since the contact entitity can be a subgrid in other entities as well, we want to restrict this behavior only to account entity. We can further lock down this behavior to a specific form on the account entity, if we want, but we are not going to do this in this instance.

function () {
    var NYR = window["NYR"] || {};
 
    NYR.addExistingContactSubgrid = function (gridTypeCode, gridControl) {
        Mscrm.GridRibbonActions.addExistingFromSubGridStandard(gridTypeCode, gridControl);
        if (Xrm.Page.data.entity.getEntityName() === 'account' &&
            gridTypeCode === 2 &&
            typeof gridControl['get_viewTitle'] === 'function') {
                var inlineBehaviour = document.getElementById('lookup_accountContactsGrid_i').InlinePresenceLookupUIBehavior;
                inlineBehaviour.setDefaultView('927E6CD8-B3ED-4C20-A154-B8BD8A86D172');
                inlineBehaviour.set_disableInlineLookup(true);
        }
    };
    
    this.NYR = NYR;
})();

Notice that we are using the name of the subgrid and the GUID of the required view. After uploading this script as a javascript webresource, we have to change the behavior of the “Add Existing” button using Ribbon Workbench. Change it to call our NYR.addExistingContactSubgrid function. In this case my webresource name is nyr_contact_ribbon.js.

Finally, publish the changes using Ribbon Workbench. Now, when you try to add contact from the subgrid in the account entity, Contacts: No Campaign Activities in Last 3 Months will be the default view.

I have used this to control the inline lookup behavior on a 1:M relationship, but the same approach can be followed for a M:M relationship as well. Notice that I have also hardcoded the GUID of the view. You can use SOAP/OData to retrieve the viewid using the viewname, to improve this code. This is an unsupported customisation, so please use it at your own risk.