Thursday, 10 March 2016

Coding Standards for Dynamics CRM

Recently I was asked by a partner for Dynamics CRM coding standards. There is a lot of coding standards for .Net and JavaScript projects. However I could not find any specific coding standards for Dynamics CRM.


After few days of attempt, I have documented coding standards for Dynamics CRM here. Please note this is not a complete list. This is meant to be a starting guide for anyone trying to use this document. Feel free to add your company's specific standards.


Feel free to comment on the blog to get the conversation going.

Sunday, 9 August 2015

Optimistic Concurrency in Dynamics CRM

When more than one user selects the same record and tries to save the record with different updates at the same time, one of the users will have a data loss. To avoid this, you can enable optimistic concurrency when saving and updating the records.


So the main difference is ability to check the version of the transaction and update only if the version number matches.Optimistic concurrency is supported on all out-of-box entities enabled for offline sync and all custom entities. For OOTB entities check if  the attribute IsOptimisticConcurrencyEnabled is set to true. For custom entities, this property is set to true by default.

Please note for Microsoft Dynamics CRM Online organizations, this feature is available only if your organization has updated to Dynamics CRM Online 2015 Update 1. This feature is not available for Dynamics CRM on-premise.

Here is the code samples:

Update if version number matches:
var account = service.Retrieve("account",accountId, new ColumnSet("name","address1_postalcode","creditlimit"));

if (account != null && account["address1_postalcode"] != null && account["address1_postalcode"] == "90210")
{
    Entity updatedAccount = new Entity(){
                                         LogicalName = account.LogicalName,
                                         Id = account.Id,
                                         RowVersion = account.RowVersion
                                        };

   updatedAccount["creditlimit"] = 1000000;
   UpdateRequest accountUpdate = new UpdateRequest(){
                                                      Target = updatedAccount,                                                   ConcurrencyBehavior = ConcurrencyBehavior.IfVersionMatches
                                                     };
    UpdateResponse accountUpdateResponse = service.Execute<UpdateResponse>(accountUpdate);
}


Delete if version number matches:
 
EntityReference accountToDelete = new EntityReference()
{
    LogicalName = account.LogicalName,
    Id = account.Id,
    RowVersion = account.RowVersion
};

DeleteRequest accountDelete = new DeleteRequest()
{
    Target = accountToDelete,
    ConcurrencyBehavior = ConcurrencyBehavior.IfVersionMatches
};

try
{
    DeleteResponse accountDeleteResponse = service.Execute<DeleteResponse>(accountDelete);
}
catch (FaultException<OrganizationServiceFault> ex)
{
    if (ex.Code == OPTIMISTIC_CONCURRENCY_VIOLATION) {…}
}

Wednesday, 5 August 2015

Multiple Rollups and service pack on same server

Have you ever wished if you can have multiple rollup on the same server? Thanks to Rafael Urbano for this trick.

Here is the steps for this:

1) Disable the organisation that you do not want to upgrade.
2) Apply the roll up / service pack to rest of the organisation.
3) Enable the organisation that you do not want to upgrade. At this time, system will ask that there are new rollups available, do you want to upgrade. Select No for this.

There you go. You have same server and multiple organisations on different roll ups. This is what deployment administrator console shows.

 
Hope this helps




Monday, 22 June 2015

Duplicate Appointments in Outlook 2013

Recently I was working on a project where service appointment and recurring appointment in client's outlook 2013 client kept duplicating itself when the appointment is tracked / created in CRM. This is what resolved the issue for us:
 
Resolution:  

1: The presence of the HKEY_CLASSES_ROOT\TypeLib\{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52} registry key.
 
Followed these steps:

1.       Exit Outlook.

2.       Click Start, click Run, type regedit, and then click OK.


3.       Locate the following registry subkey:

HKEY_CLASSES_ROOT\TypeLib\{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}

4.       Right-click on the registry key, and then select Export. Save the export to your desktop to create a backup.

5.       Right-click on the key again, and then select delete.

6.       Start Outlook.

 
2: Previous version of Office had left behind reference to an older OLB file.
 
Followed these steps:

1.       Exit Outlook.
 
2.       Click Start, click Run, type regedit, and then click OK.
 
3.       Locate the following registry subkey:
 
                                 4.       HKEY_CLASSES_ROOT\TypeLib\{00062FFF-0000-0000-C000-000000000046}
 
                              5.       Delete the version keys (e.g. 9.4  and 9.3) for any version of Outlook that is not installed on your system based on the version table provided below. For example, if you are not using Outlook 2013 then remove the "9.5" entry. If you are not using Outlook 2010 then remove the "9.4" entry. If you are not using Outlook 2007 then remove the "9.3" entry.

Outlook
Version
Outlook 2003
9.2
Outlook 2007
9.3
Outlook 2010
9.4
Outlook 2013
9.5
 
3:  Removed third party add-ins

o   Business Connectivity Services Add-ins

o   GigaTrust Desktop Client Outlook Add-ins

o   McAfee E-mail Scan Add-ins

4: Upgrade CRM client for outlook from Service Pack 1 to Service Pack 1-UR1 for CRM 2013

 
 
Note: Please backup the registry before making any changes. Also please make registry changes at your own risk.
 

Tuesday, 16 June 2015

Async maintenance job schedule

When we deploy CRM and are in a rush to go Live, we often forget to check for time the asynchronous maintenance job executes.
 
The Dynamics CRM platform's asynchronous jobs are automatically scheduled to run at a default frequency scheduled at the random start time when CRM organisation is created. By default CRM will create six maintenance jobs which are scheduled to run daily. These jobs are executed by the Microsoft Dynamics CRM Asynchronous Processing Service (maintenance).


◾Deletion Service

◾Indexing Management

◾Reindex All

◾Clean up Workflows

◾Create Audit Partition

◾Check For MUI Updates

This means that the maintenance job might execute at the peak system usage time. To avoid having performance issues it is suggested to schedule this job to run after hours.

You can use the tool available on codeplex to reschedule the jobs after hours.

Hope this helps.


 
 

Saturday, 16 May 2015

Alternate key for CRM 2015 spring release


Have you ever wished that CRM had a composite key to reference the entity data? Guess what your wishes are now granted With Spring release, CRM now makes keys available for all entities.
 
 
 
 
You can create a composite key/alternate key for multiple columns like Account Name + Account suburb or any such combinations. So the question in many people's mind would be how does this help?
 
With this, you can now define a non-clustered index in the database. This will allow quick searches as now non-clustered index can be created for alternate keys and that means table scans will not be necessary and the records can be fetched a lot faster.

This can also be used to identify data imported into CRM from external system. Please note alternate key is not GUID. It is new way to allow external systems store CRM reference.

Here is the code example which uses alternate keys

string accountNumber = "12345";
Money NewCreditLimit = new Money(5000000);
string newPrimaryContact = name1@company.com;

using (OrganizationServiceProxy service = GetOrgService())
{
    Entity account = new Entity() { LogicalName = "account",
                                    KeyAttributes = { { "new_subcode", "FABRIKAM" },
                                                      { "new_subacctcode", accountNumber } }
                                 };

    //update account
    account["creditlimit"] = NewCreditLimit;
    account["primarycontactid"] = new EntityReference("contact", "emailaddress1", newPrimaryContact)
    UpdateRequest request = new UpdateRequest();
    request.Target = account;
    UpdateResponse response = (UpdateResponse)service.Execute(request);
}

Further details on alternate keys available on following MSDN article:

https://msdn.microsoft.com/en-us/library/dn932139.aspx

Looking forward to more tightly integrated systems.