Gotcha: Optional Action Parameters

Yesterday, when I was looking into some failed tests, I discovered a quirk of action. If you invoke an action and don’t pass in the arguments that are optional, it doesn’t mean this is going to come up as null in the execution context.

Below is the action I used to replicate the behaviour.

Optional

When I execute the action and don’t set any arguments, here is what comes through in the execution context.

Argument Type Value
 Boolean  false
 DateTime  0001-01-01T00:00:00
 Decimal  0
 Entity  null
 EntityReference  null
 Float  0
 Int  0
 Money  null
 Picklist  null
 String  null
 EntityCollection  null

The interesting things to note are:

  1. Action arguments, don’t behave the same as AttributeCollection. When you retrieve an entity using the SDK, get the attribute just using the key (not GetAttributeValue), the key won’t exist in the collection, if the attribute value is null. This is not the same behaviour with the action arguments. The key will always be there in the context, even if was not set during the action invocation.
  2. The default value of action arguments = default value of the primitive type

This essentially means that if you are going to do some processing based on the action argument that is a primitive type (Boolean, DateTime, Decimal, Float, Int, String), don’t make it optional. For e.g. if you make a boolean argument optional, how would you differentiate between an action invocation with the argument set to false, and another one which did not set the argument at all?

tl;dr; For action arguments (both input and output) of type Boolean, DateTime, Decimal, Float, Int and String avoid optional.

Advertisements

Searching by Guid

When a lookup is resolved in CRM in advanced find on entity form, it uses quick find view to resolve the correct record. So, if you search for a value that is present in an attribute that is not a “Find Column” the value will not be resolved to a lookup. In this situation, you will get a red cross icon, indicating that this value has to be manually chosen.

Failed to resolve

Note in the above screenshot that I am searching by Guid of the contact. The primary key of the contact entity is “contactid”, but it cannot be added as a “Quick Find” column.

QuickFind Columns

The default find column of a custom entity will be “[publisher prefix]_name”. This is usually the “Primary field” of the custom entity, unless you have changed it during entity creation. If you just went with the default, this is what it will be. Unlike OOB system entities, which have lot of find columns defined by default, custom entity will have one find column i.e. primary field, defined by default.

In both these scenarios it is not possible to search by the primary key of the record, as indicated by the screenshot above. As a power user, you might know the primary key of the record you exactly want on the lookup. A common scenario that I personally experienced is that, I might create a fetchxml that returns a child result set, and I want to display the parent entity records from advanced find, that have the child lookup set to a particular value.

You could search by name if name is unique or your quickfind columns don’t return multiple results. If you search term returns multiple matches, you will get an yellow exclamation icon indicating that you would have manually resolve it.

Multiple Matches

In this situation where you are searching a contact, it is not uncommon for people to have the exact same name, and if you are searching by name (assuming fullname is a find column) you will end up in this scenario. I present a solution to this problem. It is a custom plugin that fires pre-operation of RetrieveMultiple message and modifies the query to enable searching by primary key.

This is how the plugin is registered.

Plugin

Registration

In this case, I want the primary key search capability only for account and contact, and hence registered steps only for these entities. You could add additional steps similarly for more entities, that you require.

Here is the functionality in action on lookup.

Advanced Find Guid Search

Here is the same behavior on normal saved view search.

View Guid Search

You can find the source code for the plugin at https://github.com/rajyraman/QuickFindManipulate

This a proof-of-concept to give a idea about this capability using RetrieveMultiple. You can extend on this to make the plugin steps configurable and add additional performance optimisations. I hope this will be a useful feature for power users.

Critical bug with Full Text search

Most of the cool new features unveiled by Microsoft, are available in CRMOnline only. But, full text search is one of the features that is OnPremise only. It was made available with CRM2015 Update 0.1. By default, this is turned off. In order to turn on this feature you’ll have to head over to “Settings” area and select “Yes” next to “Enable full-text search for Quick Find”

Full Text Search

While testing out this feature in our DEV environment, I uncovered, what I consider, a major bug with the feature. The bug is this:

If you have turned on full text search, you lose the ability to alter the length of the text fields on any customisable entity.

If this OK in your case, you have nothing to worry. For others, read on.

Replication steps

  1. Use the query below to identify the full text indexes and the entity text fields
    SELECT
      b.name AS [Table Name],
      c.name AS [Index Name],
      d.name AS [Entity Name],
      e.Name AS [Text Attribute]
    FROM sys.fulltext_indexes a
    INNER JOIN sys.objects b
      ON a.object_id = b.object_id
    INNER JOIN sys.indexes c
      ON c.object_id = b.object_id
      AND c.index_id=a.unique_index_id
    INNER JOIN EntityAsIfPublishedLogicalView d
      ON d.basetablename = b.name
    INNER JOIN AttributeAsIfPublishedLogicalView e
      ON e.EntityId = d.EntityId
    WHERE d.iscustomizable = 1
    AND e.AttributeTypeId = '00000000-0000-0000-00AA-11000000001E'
    AND e.IsLogical = 0
    AND e.IsCustomizable = 1
    ORDER BY d.name, e.Name
    
  2. Try to increase of decrease the length of any of these fields from the entity customisation area. If you try to save the attribute after increasing or decreasing the length, you will get  a generic SQL exception.

SQL Error

Our test environment, that doesn’t have full text search enabled, doesn’t suffer from this issue. I was thinking of manually deleting the full text index from the base table and then updating the attribute length, but I didn’t do so, as I haven’t fully analysed the impact of doing this.

The downloaded error file doesn’t help to identify the root cause of this issue.

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]:
System.Data.SqlClient.SqlException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #85B87978Detail:
<OrganizationServiceFault xmlns:i=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts”&gt;
<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:d2p1=”http://schemas.datacontract.org/2004/07/System.Collections.Generic&#8221; />
<Message>System.Data.SqlClient.SqlException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #85B87978</Message>
<Timestamp>2016-01-25T10:54:39.1831237Z</Timestamp>
<InnerFault i:nil=”true” />
<TraceText i:nil=”true” />
</OrganizationServiceFault>

Cause

CRM wants to drop and recreate the full text index on the entity base table, when the length of any text field in that entity is updated. When it tries to do this, SQL throws an error.

FullTextQuery

FullTextError

So, my recommendation at this stage is not to use this feature, until this bug is resolved in the upcoming updates.

 

Backing up plugin/workflow assemblies

One of the ways to quickly backup the plugin/assemblies that are stored in the MSCRM database is to use the Assembly Recovery Tool that comes with XrmToolBox. Recently, I had a situation where I couldn’t back up the assembly this way, as one of the assembly was huge and the OrganizationService was experiencing some latency issues, resulting in a slow performance of the Assembly Recovery Tool.

I followed the method below to quickly backup the assemblies straight from the database.

  1. Install CShell. I prefer this over Linqpad for quickly running C# snippets because you get intellisense for free and it also has a REPL window.
  2. Run the query which is below in SQL Server Management Studio, against the MSCRM database
    SELECT [Name],[Content] FROM dbo.PluginAssemblyBase WHERE IsHidden=0
    
  3. Right click on the result and choose “Save Result As” from the context menu and specify the file name and the location
    SSMSResults
  4. Run the code below in the CShell scratchpad
    var pluginCsv = System.IO.File.ReadAllLines(@"[FULL PATH OF THE SAVED CSV]");
    foreach(var l in pluginCsv)
    {
    	var content = l.Split(',');
    	var assembly = Convert.FromBase64String(content[1]);
    	System.IO.File.WriteAllBytes(string.Concat(@"[OUTPUT PATH FOR THE ASSEMBLY]",content[0],".dll"),assembly);
    }
    

All the assemblies should now be saved to the specified folder. You can use this technique to restore assemblies from database backups of the MSCRM database.

New calculated field functions in CRMOnline Update 1

I logged a suggestion in Connect long time back, about lack of DATEDIFF function option in calculated field (https://connect.microsoft.com/dynamicssuggestions/Feedback/Details/1086828).

Quite to my surprise, CRMOnline Update 1 (Carina) now has a bunch of new DATEDIFF functions. These are

  • DIFFINDAYS
  • DIFFINHOURS
  • DIFFINMINUTES
  • DIFFINMONTHS
  • DIFFINWEEKS
  • DIFFINYEARS

There is also an additional function “NOW”, that gives you the current datetime. According to
https://youtu.be/NJgRctOncuA?t=855 “NOW” returns SQL Server UTC Time and not the user’s local time. This is true, only if the datetime field is Time Zone Independent. If the datetime field is created as User Local, “NOW” returns user’s local timezone.

If you try to use NOW function in a datetime field with behaviour Time Zone Independent, you’ll get “You can only use a Time-Zone Independent Date Time type field” error message.

The trick to getting UTC time in this case, is to first create the datetime field as User Local, fill in the calculation field action, and only then change the datetime behaviour to Time Zone Independent. Also note that, it is possible to change the datetime behavior from User Local to Time Zone Independent, but not the other way around (from the UI).

I created two calculated fields using NOW function, one is User Local and one is Time Zone Independent. After doing an Advanced Find with the attributes, here is the result.



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

This is the Advanced Find result

These great additions in the Spring Update, make calculated fields more powerful than ever.

Quicktip: Install .net 4.5.2 before developing for CRM2015

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 “Install-Package Microsoft.CrmSdk.XrmTooling.CoreAssembly” from the PM console without any issue. But when you try to build the application I got these compilation errors.

The root cause of these errors is because the project is not targetting .net 4.5.2. Download .net 4.5.2 from http://www.microsoft.com/en-us/download/details.aspx?id=42637 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.

Calculated Fields in CRM 2015

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.

This the business rule to perform the division.

 

When you save the record an error is displayed.

This is the actual error

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>

The calculated field that performs the division works without any issue.

Interesting behaviours that I encountered below.

Scenario 1: Calculated field to divide two integers and the result of the operation is float e.g. : 5 / 2

Result: The result is rounded up to the closest int.

Result1
 
Scenario 2: Calculated field – Divide by zero

Result: No divide by zero exception. The result is blank.

Result2

Scenario 3: Calculated field of type text, with calculation using decimal fields.

Result: No error. Result of the operation is can be assigned to the string field.

Result3

Conclusion: 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.