Posted on 24. May 2015

Turbo Forms: Get your JavaScript ready for CRM2015 Update 1

With the introduction of 'Turbo Forms' in CRM2015 Update 1 I thought I'd give you a heads up on what you'll need to address in your JavaScript to support this new form rendering engine. The Dynamics CRM Team Blog has a very good article on the changes but there have been some misunderstandings of the statement 'we have parallelized as many operations as possible'. In actual fact the script loading of custom web resource scripts has not really changed since CRM2013 - It remains the same as I describe in my CRM2013 Script Loading Deep Dive. The operations that are parallelized with turbo form rendering are the internal form load operations rather than custom ones. Custom JavaScript loading has always been parallelized since CRM2013.

Turbo Form Page Differences

Before Turbo Forms both global scripts and your custom web resources would have been loaded into a content IFRAME within the main window each time you navigate between records.

The biggest change with Turbo Forms is that the content IFRAME is kept in memory and re-used for performance reasons. This parent content IFRAME is even kept in memory between navigation between different entity types. Any custom JavaScript is then loaded into a child IFRAME (via the ClientApiWrapper.aspx page) so that when you navigate between records they are re-loaded.

SparkleXRM solutions already have a load order mechanism that ensure that your custom scripts are loaded in order that they are needed.

Impact on unsupported code

If your JavaScript is using only supported SDK calls then there will be no impact from this new loading mechanism. Sometimes it is necessary to use unsupported functions or referencing parameters of the Content IFRAME (such as the query string). Since your custom JavaScript is now running in the context of the ClientApiWrapper (rather than the content IFRAME) any reference to window methods such as window.openStdWin or window.location.href will fail. In order to access these objects you will need to reference parent.window.

The ribbon workbench 'how-to' article that shows starting a dialog from a ribbon button does infact use openStdWin to ensure consistency with the out of the box dialog experience. I have updated the code to use the parent window when required.

Footnotes

There are a couple of other notable aspects of Turbo Forms that I thought I'd point out:

IFRAMES that are collapsed by default are not sized correctly.

If you have an IFRAME or HTML Webresource inside a Tab that is collaposed by default you will find that they are not sized correctly when the tab is expanded. This will be fixed in an upcoming update but until then you will need to show the tab by default and collapse when the form is loaded.

entityType vs typename

Turbo Forms have dropped the typename attribute of Lookup values.

In the past, the following code would return the same:

Xrm.Page.getAttribute("parentcustomerid").getValue()[0].typename
Xrm.Page.getAttribute("parentcustomerid").getValue()[0].entityType

With Turbo Forms only the documented entityType is available. The typename attribute was left over from the CRM4 days and just had not been removed until now!

@ScottDurow

 

Posted on 12. May 2015

Introducing SparkleXRM Metadata Server

Metadata Server Logo

Speed up your HTML web resources by caching metadata such as localised field labels and options sets.

If you've developed an HTML web resource for Dynamics CRM that includes field labels, option sets or any other element that is stored in the Dynamics CRM metadata then you’ll know about the delay each time the your UI is rendered whilst information is downloaded from the server. You could of course hard code this information in your JavaScript but you'd suffer higher maintenance costs especially when supporting multiple languages.

The SparkleXRM Metadata Server allows dynamic expressions to be included in JavaScript Web Resources that are evaluated on the server and then cached on the client side.

/*metadata
var fieldLabel = <@contact.fullname.DisplayName@>;
metadata*/

This will output and cache the following on the client (for an LCID of 1033):

var fieldLabel = "Full Name";

Learn more about the SparkleXRM Metadata Server!

Posted on 2. May 2015

Building a Refreshed Connection UI using SparkleXRM

I've now published all 5 videos in this series. 

If you find yourself needing to create HTML Webresource in Dynamics CRM then I'm sure you will find something here of interest. Part 5 shows how to use the new SparkleXRM Metadata Server that I'll be publishing a post on very soon.

Part 1 - Creating your first SpakleXRM Project

Part 2 - View Model Form Data Binding & Unit Testing

Part 3 - Adding an Editable Grid

Part 4 - Pulling it all together

Part 5 - Adding multi-language support

Have fun!

@ScottDurow

Posted on 22. April 2015

Building Rich UI Extensions for Dynamics CRM using SparkleXRM

Posted on 10. April 2015

Can I do that (in Dynamics CRM) ?

I'm sure by now that you've seen the new hierarchical visualisations in Dynamics CRM 2015. By clicking on the little icon in lists or on a form you can see the records graphically laid out. In true Dynamics CRM style anything you can do through the user interface is accessible through the SDK and so we now have the ability perform fetchXml queries using the above, eq-or-above, under & eq-or-under conditions. These new search criteria will find records up to a maximum of 100 recursions for a single hierarchical relationship.

Take a look at the excellent SDK topic Query hierarchical data on the subject.

I have found that when some users see the cool looking Dynamics CRM Online logon page they will ask 'Can I do that?!' I thought I would answer that question with a new SparkleXRM sample solution. Take a look:

Installing Network Visualisations (CRM 2015)

  1. Import SparkleXRM - SparkleXRM_7_2_3_managed.zip
  2. Import NetworkView - NetworkView_1_0_4_alpha_managed.zip
Usual MIT license applies!

Known Issues

For a list of known issues and reporting new ones please use the GitHub repository.

Thanks to CRMCAT and Jukka Niiranen for all the help and feedback so far.

Have Fun!

@ScottDurow

Posted on 9. April 2015

Control Async Workflow Retries

The Dynamics CRM Async Server is a great mechanism to host integrations to external systems without affecting the responsiveness of the user interface. Once such example is calling SharePoint as I describe in my series – SharePoint Integration Reloaded.

A draw back of this approach (compared to using an integration technology such as BizTalk) is that any exceptions thrown during the integration will simply fail the workflow job with no retries. You might already know that the Async Server does in fact have a retry mechanism built in as described by this excellent post from the archives - http://blogs.msdn.com/b/crm/archive/2009/03/25/when-do-asynchronous-jobs-fail-suspend-or-retry.aspx. As you'll see from this article there are some built in exceptions where CRM will automatically retry a number of times as defined by the 'AsyncMaximumRetries' deployment property. The interval between these retries is defined by the 'AsyncRetryBackoffRate' property.

So how can we make use of this retry mechanism with our custom code?

There is an undocumented and unsupported way of using this retry mechanism in your custom workflow activities. I first used this technique back in the CRM 4.0 days and I'm pleased to report that it still works with CRM 2015!

Although unsupported, the worst that could happen is that the workflow would stop retrying in future version of Dynamics CRM and revert to simply reporting the exception. However it still wouldn't be a good idea to rely on this functionality for mission critical operations.

So…plz show me the codez…

catch (Exception ex)
{
    // TODO: Rollback any non-transactional operations

    OrganizationServiceFault fault = new OrganizationServiceFault();
    fault.ErrorCode = -2147204346; // This will cause the Async Server to retry
    fault.Message = ex.ToString();
    var networkException = new FaultException(fault);
    throw networkException;
}

When an exception is thrown by your custom workflow activity you'll see the workflow enter into a 'Waiting' state and the 'Postpone until' attribute will be set to the time when the retry will take place. Once the maximum number of retries has been performed, it will enter the 'Failed' status.

You can use this technique to ensure that any temporary integration failures such as service connectivity issues will be dealt with by a graceful retry loop. It only remains to ensure that you before throwing the exception you rollback any operations performed already by your code (such as creating records) so that your retries will not create duplicate records.

Hope this helps!

@ScottDurow

Posted on 25. March 2015

Using the Configuration Data Migration Tool with non-unique display name values

Just thought I would share this little tip to prevent someone else having the same issue:

The Configuration Data Migration Tool is a great way of moving records such as custom auto number settings from one organization to another. You can find it in the SDK under SDK\Tools\ConfigurationMigration.

When configuring the data schema, you are prompted to select the entities and the attributes that you would like to export and then eventually import. This seems like this is all that is required before hitting 'Save and Export' – but be warned there is one more important step if your data does not have unique display name values.

In my example I had two records that had the same name and they already existed in the target organization. Normally, the tool will use the display name attribute to perform a lookup rather than use the primary unique identifier for the record. The result will be that the same record will be updated twice in the target, rather than the two separate records being updated accordingly.

To ensure that the primary name field is not used as the lookup on the target system you must select 'Tools->Configure Import Settings'. This then gives you the option to select the primary key field that you want to use other than the display name:

You can no click 'Save' and export your data knowing that the primary unique identifier field will be used to match the records between the source and destination.

The xml schema file created adds the magic 'updateCompare' attribute to the xml and you are good to go!

<field updateCompare="true" displayname="Counter" name="xbitz_counterid" type="guid" primaryKey="true" />

You can learn more about this very useful tool here - https://technet.microsoft.com/en-us/library/dn647422.aspx Hope this helps!

@ScottDurow

Posted on 11. March 2015

SparkleXRM now available on NuGet

I've just published the latest version of SparkleXRM on NuGet to make it easier to use from within Visual Studio.

You can simply add a NuGet reference to SparkleXRM and the dependancies will be pulled in as well.

PM> Install-Package SparkleXRM

Once installed, the Sparkle XRM assemblies will be referenced in your project and the latest managed solution can be found in the '\packages\SparkleXRM.7.2.3\content' folder.

Currently there is the CRM2015 version 7.2.3 available but I'll add the 2011/2013 version as well shortly.

Posted on 16. February 2015

Business Rules & “SecLib::RetrievePrivilegeForUser failed - no roles are assigned to user”

When publishing your Ribbon Workbench solution you may receive the following error:

"SecLib::RetrievePrivilegeForUser failed - no roles are assigned to user."

The first step in diagnosing these issues is to try and export the same solution using the CRM solutions area and then immediately re-import to see what error is shown. This is exactly what the Ribbon Workbench does behind the scenes.

When doing this you might see:

Upon Downloading the Log File you'll see that the error occurs on a 'Process' and the same error message is shown as reported by the Ribbon Workbench. The User ID is also given which can be used in a URL similar to the following to find the user record causing the issue.

https://<orgname>.crm.dynamics.com/userdefined/edit.aspx?etc=8&id=%7b<User GUID>%7d

You will most likely discover that this user has been disabled or has no roles assigned – this could be that they have left the company or changed job role. You will need to find any Workflows or Dialogs that are assigned to them and re-assign to yourself before you can import the solution.

In most cases, you should not include Dialogs or Workflows in the solution that is loaded by the Ribbon Workbench since this only slows the download/upload publish process down. There is one exception to this – and that is Business Rules. Business Rules are associated with their particular entity and cannot be excluded from the solution. Oddly like Workflows and Dialogs they also are owned by a user but it is not shown in the user interface – nor is there an option to re-assign. There is a handy option on a user record that allows you to 'Reassign Records'

You would think that this would reassign any Business Rules but unfortunately you'll get the following error:

"Published workflow definition must have non null activation id."

The only way to reassign these Business Rules is to perform an advanced find for Processes of Type 'Definition' and Category 'Business Rule'

The results can then be reassigned to yourself using the 'Assign' button on the results grid.

@ScottDurow

Posted on 3. February 2015

The dependent component Attribute (Id=transactioncurrencyid) does not exist. Failure trying to associate it with Workflow

I recently answered a question on this error on the Community forms and coincidently I've just come up against exactly the same issue!

When importing a solution you receive the error 'There was an error calculating dependencies for this component' and on downloading the log you see the full message similar to:

The dependent component Attribute (Id=transactioncurrencyid) does not exist. Failure trying to associate it with Workflow (Id=<GUID>) as a dependency. Missing dependency lookup type = AttributeNameLookup.

Although this message can appear for other attributes, this post is specifically to do with the transactioncurrencyid attribute being referenced.

When you add a money field to an entity CRM automatically adds a N:1 relationship to the currency entity to hold the currency that the value is stored against. The foreign key attribute is always named transactioncurrencyid.

In this increasingly 'agile' software development world attributes are added and remove fairly regularly during the development phase. If a money field is added to an entity and then removed, the transactioncurrencyid attribute is not removed. Because the relationship automatically created by the system it is not created when deploying to another environment via a solution import because there are no money fields. This leads to your development environment having the additional relationship. This wouldn't cause a problem apart from that when you create a workflow with a 'create' or 'update' step, the currency field is usually pre-populated with the default currency. Consequently when you try to import this workflow into another organization that does not have the currency relationship you will see this error.

The solution is to either delete the transactioncurrencyid field from your development environmentm and from the workflow create/update steps or simply add a dummy currency field to your target environment in order to create the relationship to currency.

@ScottDurow