Testing CRM rollups and .NET versions

In this article I will talk about testing patches and how .NET versions can cause odd errors.

Rollups and CRM Version

I had a customer who was using CRM 2013 Service patch 1 and wanted to test their customizations still worked when CRM 2013 SP1 rollup 3 was applied.

Testing a new CRM service pack or rollup involves using a new server and CRM instance.

You can have many CRM organisations deployed on one CRM server but if you upgrade the CRM server it will effect all the CRM organisations and I don’t know any method to roll back rollups.

Why can’t you rollback CRM versions

To understand the question you need to think what happens (could happen) when you apply a rollup

  • Possible changes to the database tables
  • Update to CRM SDK
  • Depreciating certain functional in CRM SDK

Database changes

Microsoft might change the whole structure of the CRM database between service patches and rollups, which is one of the reasons Microsoft recommends you do not write any code/customizations/reports which run directly against the CRM database.  Microsoft provide filtered views and the CRM SDK for you to integrate the CRM database.

I think during the CRM 2013 update Microsoft used to have base and extension tables for each entity. e.g.

  • entitynameBase
  • entitynameExtensionBase

e.g.

  • accountBase
  • AccountExtensionBase

Here is some more information on the merging of tables, which explains how you can run the table merging as a separate job but you have to do it.

Run the base and extension table merge as a separate operation

I have written before about unsupported customizations before – Why you shouldn’t put unsupported customizations in Microsoft Dynamics CRM.  The primary reason you should avoid unsupported customizations is if you have to escalate an issue to Microsoft they offer limited support if you have unsupported customizations (because those customizations might be the cause of the behaviour/bug)

New functionality in CRM SDK and CRM

Usually (but not always)

  • Roll ups contains fixes
  • Service packs contain fixes and new functionality

New functionality doesn’t usually break anything but sometimes existing functionality might change.

The key point is the CRM SDK will have changed,

Old CRM SDK functionality depreciated

With one hand Microsoft giveth new functionality and the other hand they take functionality away (depreciate).

You should always read the What’s new for a new release of CRM – Why you should read the What’s new for developers because it lists not only the new functionality but includes what’s being depreciated in Javascript and CRM SDK.

Applied patches but stuff not working

I applied the rollup to CRM 2013 SP 1 rollup 3 but when I tried to test CRM, I noticed I was getting unusual errors.  The core functionality of CRM was working but I was getting errors when the plugins triggered calls to WCF web services.  Below is the error

The Web Service plug-in failed in OrganizationId: 3666c2e6-04f4-e411-80c9-000c292122be; SdkMessageProcessingStepId: 2ccabb1b-ea3e-db11-86a7-000a3a5473e8; EntityName: incident; Stage: 30; MessageName: Create; AssemblyName:
Inner Exception: System.TypeLoadException: Could not load type ‘System.Runtime.CompilerServices.ExtensionAttribute’ from assembly ‘mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.
at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)

To find this error I had to turn on tracing and look into the event logs because CRM was not giving much information.

I have highlighted the key part of the error.

This article was useful

Could not load type ‘System.Runtime.CompilerServices.ExtensionAttribute’ from assembly ‘mscorlib

This seemed a classic DLL type error, this usually occur when you there are differences between .NET versions or DLL’s deployed.

In this particular scenario I could compare the .NET version installed on the working CRM environment and the .NET version and other DLL’s in the new upgraded environment.

So I needed to check the .NET version, Microsoft has a great page on this

How to: Determine Which .NET Framework Versions Are Installed

Be careful because you have to read it carefully.  I was checking the .NET versions in regedit (full instructions in the link above) and the folder said v4.  I was expecting a 4.5 folder, so I assumed it was version 4.

Its a better to know facts rather than making assumptions particularly when trying to find a problem.  In the example above I assumed the .NET versions where the same, which meant I then wasted time investigating other parts of the server and DLL’s looking for potential problems.

If I had read the article more carefully  it more carefully I would have noticed this very important section

The value of the Release DWORD indicates which version of the .NET Framework is installed.

 

The folder will be v4 but if this has been updated it will have a new Release registry value and the number in this registry settings tells you what version of .NET is installed

.NET versions

 

I found there was a DWORD value in the working CRM Server which indicates I had 4.5.1 installed

378675 .NET Framework 4.5.1 installed with Windows 8.1 or Windows Server 2012 R2

I checked on the server I was updating CRM 2013 SP 1 to rollup 3 and it only had .NET framework 4

What was happening was the web services were compiled with .NET 4.5 but when they tried to run on the new server it couldn’t find the correct dll versions, this caused the odd errors.

What I learnt

Don’t make assumptions – Know don’t assume.

If web services are not working check the .NET versions and look for the secret DWORD registry setting Release.

 

Hosk’s Top CRM Articles of the week – 24th July

Article of the Week

Asynchronous Batch Process Solution Revisited – part 1

Asynchronous Batch Process Pattern: Part 3

I enjoyed reading these two articles

Best of the Rest

CRM 2015 – Understanding impersonation in plugins and knowing when to use it

A look at plugins and understanding impersonation, when, why and how to use impersonation

Updating and Publishing webresources directly from Visual Studio

A tool to update web resources from Visual studio

MICROSOFT ANNOUNCED ITS CERTIFICATION FOR DYNAMICS CRM ON-PREM RUNNING AZURE IAAS

It’s finally certified

CRM 2013 – Workflow error AccessCheckEx

The Hosk got an error, find out how I worked out the cause and my solution

Querying More than 5000 records in Dynamics CRM

Interesting article talking about paging when selecting lots of records

CRM 2015 – What is the CRM Outlook reading Pane?

The CRM outlook reading pane caused me problems this week

Visual Studio 2015 Shared Projects and CRM Plugins Development

Excellent new functionality in Visual Studio 2015, help you get round the dll/ilmerge problems

CRM 2015 – Understanding CRM Metadata

What is Metadata in CRM 2015

Tracking the Movements of a Case

Leon Tribes shows how a no code solution to tracking the history of a case.

Microsoft Dynamics CRM Mobile SDK Update and Azure Mobile Connector SDK

CRM SDK for Mobile and Azure

CRM 2013 – Understanding SystemJobs and Async Plugins

Understanding System jobs and async plugins

Using Windows Resource Monitor to Find Unusual Performance Bottleneck

Great use of windows resource monitor to diagnose a problem

How to cascade activate / deactivate (SetState) in CRM

Do you know your cascading

Getting the CRM Developer toolkit working with Visual Studio 2013

Tutorial to get CRM Developer toolkit working with visual studio

programming

Announcing the latest improvements for the F12 developer tools in Windows 10

Group Flow in Software Development

7 Tools to help you gather better software requirements

Building your mental toolbox for solving coding problems

Other articles interesting the Hosk

free minding hacking book

awesome mind maps/sketches of books

Why Exercise Won’t Make You Thin

Billy Beane on Making Better Decisions and Avoiding Biases

Mental Model: Regression to the Mean

BBC iPlayer ‘watched by more than 60 million people outside the UK for free’

“How To Pick The Perfect Book Title”

short master course on Thinking about thinking

Previous top picks

Hosk’s Top CRM Articles of the week – 17th July

Useful Hosk Links

Hosk list Of CRM 2013 Tools

A list and review of CRM 2013 tools, this will probably work in CRM 2015 as well

Hosk’s CRM Developer Articles

A collection of my favourite CRM Developer articles I have written

MB2-703 – CRM 2013 Customization and Configuration Certification Information

All the CRM 2013 content to help you pass the exam

HoskWisdom – Hosk Developer Quotes

 Words of Wisdom from the Hosk.  I have written over 900 articles, surely I should have said a few memorable things

CRM 2015 – What is the CRM Outlook reading Pane?

I have started using CRM 2015 SP1 and the navigation tweaks are awesome.  So I will congratulate Microsoft on the navigation tweaks and wonder how they got it so wrong in CRM 2013!

The Outlook reading pane is a pain, that’s not entirely true but for an hour today it caused rampant confusing and gnashing of teeth.
I will explain the problem I had first.
CRM Developer Joe was perplexed because the CRM form being shown in Outlook wasn’t the same as the CRM form he was customizing.  He asked me why, why, why, why was this happening.
The contact form looked different than the information in outlook, except if you clicked on the contact it opened a CRM form which looked the same?!?!?!
Contact form in CRM Web
contact form

Outlook contact form but it still has fields which were removed from the contact form.
contact form outlook

So what’s the problem?

I haven’t used the CRM outlook add-in for ages, so I had to do a bit of clicking and looking around.

Searching the internet didn’t bring up anything useful, which was odd because if this was a problem then lots of people would have mentioned it.

Think, Think, Think, Think

I wondered if Outlook wasn’t refreshing properly but after un-installing and installing it still didn’t fix it.

I ended up clicking around and looking for settings, I then clicked on view.  Hmmmm Customize Reading Pane, what does that do?

custom reading pane

So I clicked it

custom reading pane 1

 AHA

The data which was being shown was the Reading Pane and the data it shows are not customizable (except you can remove some sections if you want).

What is the CRM Outlook reading pane?

The reading pane is a quick way to view contact information in a read only view.  It’s useful Microsoft have provided some quick view functionality, frustrating you can’t edit it and puzzling I couldn’t figure out where this information was coming from.

If you think of the CRM reading pane working like the normal Outlook reading pane, which shows you some details about an email without you having to open/read the email.

The CRM reading pane works in a similar way, showing you some details about the contain without having to open the contact record.  This works OK except when you have customized the contact record significantly because the new fields won’t be shown in the reading pane and fields you have removed from the form will be displayed

More information

Customize the Reading Pane in CRM for Outlook

Navigating the CRM Outlook Client

How to Hide Tabs in Reading Pane for Dynamics CRM Outlook Client

CRM 2013 – Workflow error AccessCheckEx

I was investigating a bug on CRM 2013 , I got the exception below

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess Detail:
<OrganizationServiceFault xmlns:i=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns=”http://schemas.microsoft.com/xrm/2011/Contracts”&gt;
  <ErrorCode>-2147220891</ErrorCode>
  <ErrorDetails xmlns:d2p1=”http://schemas.datacontract.org/2004/07/System.Collections.Generic”&gt;
    <KeyValuePairOfstringanyType>
      <d2p1:key>OperationStatus</d2p1:key>
      <d2p1:value xmlns:d4p1=”http://www.w3.org/2001/XMLSchema&#8221; i:type=”d4p1:string”>0</d2p1:value>
    </KeyValuePairOfstringanyType>
    <KeyValuePairOfstringanyType>
      <d2p1:key>SubErrorCode</d2p1:key>
      <d2p1:value xmlns:d4p1=”http://www.w3.org/2001/XMLSchema&#8221; i:type=”d4p1:string”>-2146233088</d2p1:value>
    </KeyValuePairOfstringanyType>
  </ErrorDetails>
  <Message>SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess </Message>
  <Timestamp>2015-06-23T10:02:24.458209Z</Timestamp>
  <InnerFault i:nil=”true” />
  <TraceText>

[Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.SyncWorkflowExecutionPlugin]
[0dac4467-fb18-e511-80ca-000c292122be: ]
Starting sync workflow ‘Task-Workflow’, Id: 04ac4467-fb18-e511-80ca-000c292122be
Entering ConditionStep1_step: If  Process contains data and is active
Entering SetStateStep4_step: Change record status to completed
Sync workflow ‘Task-Complete’ terminated with error ‘SecLib::AccessCheckEx failed. Returned hr = -2147187962, ObjectID: f115e97d-8e19-e511-80ca-000c292122be, OwnerId: 89ed0bdd-7ecd-e411-80c7-000c292122be,  OwnerIdType: 9 and CallingUser: 2ed69167-0bcf-e411-80c7-000c292122be. ObjectTypeCode: 4200, objectBusinessUnitId: 5f964320-05f4-e411-80c9-000c292122be, AccessRights: WriteAccess ‘
</TraceText>
</OrganizationServiceFault>

Initial thoughts on the Error

I got this error and there were a few things I found interesting

This error was surprisingly informative

The error was thrown by a non code workflow but the cause of the error was thrown by a GUI workflow which was being triggered when a workflow tried to assign an activity.

I was impressed by the level of logging which was generated by a GUI/non code workflow.

I had never thought about it but this line

Microsoft.Crm.ObjectModel: Microsoft.Crm.ObjectModel.SyncWorkflowExecutionPlugin

indicates CRM runs the GUI workflows using code, which must translate the actions into code. This is obvious but I hadn’t thought about it, until seeing the error.

You can use the callerid to find what user is doing the update and check what security roles the user has.

EntityTypeCode

In the error message you can see it mentions ObjectTypeCode

CRM 2011/2013 – Javascript to get the object type code of an entity

Each entity has an individual typecode, this CRM SDK page shows you the values of the default entities

Entity Type Code 4200 is ActivityPointer, which is interesting because the problem was being caused by an update to a task record.

Clues

AccessCheckEx failed – AccessCheckEx is something to do with security and access

In the error message you can see

AccessRights: WriteAccess

This is clearly telling us the user doesn’t have Write access, e.g. the user isn’t allow to update a certain

What was the cause

This bug was partly caused by the complexity of the CRM solution and the different customizations.

Solution complexity refer to not only the customizations which exist in the solution but the number of different customizations.  When a CRM solution has lots of different customizations e.g. workflows, plugins, business rules being triggered at the same time it makes it difficult to understand what is changing a value.

Below is what was happening

  1. A task was updated then saved
  2. This triggered a pre plugin on the task entity
  3. The plugin assigns the case record
  4. A plugin was triggered on assign of the case, which assigned all the open tasks to the new case owner
  5. The plugin(s) finished
  6. A workflow was triggered, which tried set the task to complete.

The error was thrown because the workflow was trying to update the task but the user only had privileges to update tasks they owned.

The reason this bug suddenly appeared was because the assign plugin was added and it wasn’t picked up in DEV testing because developers tested the code using users with System Admin privileges, which I have talked about before

The System Administrator role is a benefit and a curse to CRM developers

It’s tricky to test the effect of adding plugins

Having lots of different types of customizations adds to the complexity of your CRM solution, complex solutions are difficult to debug, understand and extend.

The Solution

Usually with bugs where the user doesn’t have the right security privilege the easy answer is to give the user role those security privileges.

For this bug it wasn’t the correct solution because the users only had access to tasks they owned and we didn’t want to suddenly give them permissions to update tasks they didn’t own.

The plugin code was running in a PRE plugin, so I couldn’t move the task completing code into this plugin.

The bug was becoming more tricky because I did want to keep the case assigning code in their but I didn’t want the assigning case plugin to run and assign the task to the new case owner because the task was about to completed.

My solution was to stop the assign plugin being triggered if was called by another plugin

Read how to do that in the blog below

CRM Plugins – Stopping infinite loops and understanding PluginExecutionContext.Depth

I then created a post task plugin to complete the task.  I didn’t need to do this but it seemed it would be easy to understand if all the changes were made by plugins.

There was an unsuccessful fix when I used impersonation to close the task as System Admin but the users didn’t like the tasks being closed by System Admin, they wanted the user who updated the task to complete the task.

You can read about Impersonation in plugins in the blog post below

CRM 2015 – Understanding impersonation in plugins and knowing when to use it

CRM 2015 – Understanding impersonation in plugins and knowing when to use it

Plugins are usually set to run as the calling user but sometimes you need to run a plugin with System User privileges.

Before I explain how, we should first look at the why and how you impersonate users inside a plugin

I have been writing a bit about plugins recently

For some step by step guides to creating plugins check out the CRM Code examples section on the page Hosk’s CRM Developer Articles, I created some Youtube videos CRM 2013 Plugins

What is impersonation

When you create a plugin in CRM (step by step blog post here) you write an execute method which gets passed in

IServiceProvider serviceProvider

This has lots of variables and objects such as

  • IPluginExecutionContext
  • ITracingService
  • IOrganizationServiceFactory

You use the IOrganisationServiceFactory to create a IOrganizationService.  The IOrganizationService is the CRM SDK, it provides you access to CRM programmatically .  CRM developers use the IOrganizationService (which I will often call CRMService) to

  • CRUD operation – Create, Retrieve, Update, Delete records in CRM
  • Assign records
  • Change status
  • pretty much everything you can do in CRM

Here is the code to create the IOrganizationService, taken from the Plugin class of the CRM Dev toolkit

// Obtain the Organization Service factory service from the service provider
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

// Use the factory to generate the Organization Service.
this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId);

When creating your plugin you will notice there is a Run in Context setting, most of the time you will choose to Run In Context of Calling User.

Create Account Plugin 1

99 percent of the time Calling User is the right choice

It’s usually the right choice to use the Calling User because any updates, retrieves or any interaction with CRM data will be done using the calling users identity and privileges.

If you visualize a plugin as an automated extension of the CRM form, it’s likely you want the the code in the plugin to run with security privileges as the calling user.  It allows you not to abdicate the need to apply security to the plugin code and pass this off the users security profile and CRM.

The PluginExecutionContext (which I explain in this blog post) has the field called UserId.  We pass this to the IOrganizationFactory to create an IOrganizationService with the user who initiated the plugin.  The good news is the CRM Dev toolkit does all this for us, so we can just chill out and get the IOrganizationService and work on the business logic.

// Use the factory to generate the Organization Service.
this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId);

Running the CrmService (IOrganizationService) as the calling user means you are interacting with the data in CRM as the calling user, which means

  • The IOrganizationService can only retrieve data the user can retrieve
  • When IOrganizationService updates, creates records they are stamped with the calling user
  • The plugin cannot do anything the calling user cannot do

The calling user setting adheres to the security role assigned to the calling user, integrity of your precious CRM data is kept intact.

Why impersonate System User

If running plugins as the calling user is so good, why impersonate other users or system admins.

  • What if you need to retrieve records the user doesn’t have access to?
  • What if you need to update records the user doesn’t have access to?

You might be thinking, “if the user doesn’t have access to those records, maybe the plugin shouldn’t be updating them”.

It’s a point to consider point but sometimes you want to create records or update records based on the action/status of an entity to move the code to the next stage/state.

Sometimes you want to assign a record to another user when a record goes to a certain state but you wouldn’t want users to be able to assign records.

How is running in context different from impersonation

The running in context setting on a plugin mentioned early runs the whole plugin in that context.

Impersonation allows you to run a small section of code in another context.

Impersonation gives the CRM developer more flexibility to target a particular action in a plugin they would like to run with elevation permissions.  The rest of the plugin actions can be run as

Dangers of impersonation

The downsides of impersonation is it potentially gives users running the plugin\custom workflow enhanced security privileges which could lead who we don’t want updating\deleting records doing exactly that.

When using impersonation in plugins consider accountability and audit trails.  When a plugin impersonates a system user or a different user, the impersonated user will update those records.  It can be confusing/worrying for users when looking at audit records to see System Admin updating records.

I’m sure there have been thousands of support calls querying why System Admin has been updating records.

Impersonation Code

Easy way to impersonate System User is to pass null to the CreateOrganizationService and it will run as System user, find out more in this CRM SDK article

// Use the factory to generate the Organization Service.
OrganizationServiceImpersonated = factory.CreateOrganizationService(null);

You can pass in a different user Id to the CreateOrganizationService to create an IOrganizationService

IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.InitiatingUserId);

The sample code in the CRM SDK article impersonates using OrganizationServiceContext.  I personally have used this

Sample: Impersonate using the ActOnBehalfOf privilege

// Retrieve the system user ID of the user to impersonate.
OrganizationServiceContext orgContext = new OrganizationServiceContext(_serviceProxy);
_userId = (from user in orgContext.CreateQuery&lt;SystemUser&gt;()
where user.FullName == "Kevin Cook"
select user.SystemUserId.Value).FirstOrDefault();

// To impersonate another user, set the OrganizationServiceProxy.CallerId
// property to the ID of the other user.
_serviceProxy.CallerId = _userId;

Impersonating during plugin-in registration

You can impersonate a user during plugin-registration but I’m not entirely sure why you would do this, so I’m not going to talk about.  Most CRM developer will impersonate someone inside a plugin.

If you want to learn more read

Impersonate another user

and the articles in the futher reading section

Why, What, Where, When

What is Impersonation

Impersonation in plugins/custom workflows is creating an IOrganisationService as a different user

Why use Impersonation

Use impersonation when you need to update/retrieve/delete/Create records users security roles doesn’t let them.

Where

If you don’t want to increase users security roles but still want the plugin to do a particularly action.  e.g. delete a record

When

You use impersonation in plugins/customer workflows

Further reading

Scott Durow has an excellent article on Impersonation

User Impersonation in Plugins, Workflow and Dialogs

CRM SDK 2015 impersonating User in plugins

Dave Berry does a good job explaining Impersonation – CRM Impersonation Explained

Awesome Pixar impersonation picture from here

Hosk’s Top CRM Articles of the week – 17th July

Article of the Week

The article of the week is my trilogy of articles on plugin code

  1. Are your CRM plugins creating technical debt?

  2. Are CRM Developers are afraid of creating classes?

  3. How to find classes

The articles look at the effect of creating plugins and putting all the code inside the plugin class, the benefits of creating classes and how to find classes when creating code.

Non Hosk article of the week

Dynamics CRM and ILMerge: The Easy Way to Merge DLLs for Plugins

It’s an old article but a good step by step guide to using ILMerge

Best of the Rest

check out the plugin tracing in CRM 2015 sp1

The ability to see the trace file in plugins will dramatically help investigating live issues.

CRM 2013 – Understanding Auditing, Tips, Tricks and Gotchas

A good long look at auditing by the Hosk.

How to handle Nulls in Dynamics CRM Calculated Fields

Interesting article on handling nulls in calculated fields

CRM 2013 – Javascript null setting oddity

A Hosk article investigating why a field wasn’t being set but delves into requirement levels and debugging

Microsoft acquires FieldOne, global provider of field service management solutions for the enterprise
video

Another new business purchased by Microsoft

Dynamics CRM: Extensions to Improve IOrganizationService

Good use of extensions to ease CRM Development

What are Preview features and how do I enable them?

New preview functionality has been added to CRM 2015, check it out

Accessing related entities fields in Calculated Fields formulas in Microsoft Dynamics CRM 2015 Online Update 1

Debugging Plug-in Made Easy for Dynamics CRM Online

A step by step guide to debugging plugins using the plugin registration tool

Microsoft Dynamics CRM not working? check these common causes

What to check if CRM stops working

Restrict customer lookup to select a specific entity records in CRM 2013/2015

Adding filters to lookups in Javascript

What’s new in CRM 2015 SP1 for developers, customizers and admins

A run down of the new features in CRM 2015 SP1

programming

Get off Your Horse and Stop Coding like a Cowboy

Second System Syndrome

interesting discussion – Over 40 years, has Software Gotten Better or Worse?

Other articles interesting the Hosk

How Bold Entrepreneurs Are Breaking $1 Million In One-Person Businesses

Microsoft ruined Nokia – WHY. Microsoft and Nokia – a marriage made in hell?

How Changing Our Product Team Structure Doubled Productivity

Annoying practices of bad recruitment consultants

Microsoft marketing manager plays the blues

Elon Musk’s high-speed Hyperloop train makes more sense for Mars than California

Here’s what happens to your brain when you give up sugar for Lent

The Stoic: 9 Principles to Help You Keep Calm in Chaos

teaching maths Asian style

What I learned from a McDonald’s Manager

Previous top picks

Hosk’s Top CRM Articles of the week – 10th July

Useful Hosk Links

Hosk list Of CRM 2013 Tools

A list and review of CRM 2013 tools, this will probably work in CRM 2015 as well

Hosk’s CRM Developer Articles

A collection of my favourite CRM Developer articles I have written

MB2-703 – CRM 2013 Customization and Configuration Certification Information

All the CRM 2013 content to help you pass the exam

HoskWisdom – Hosk Developer Quotes

 Words of Wisdom from the Hosk.  I have written over 900 articles, surely I should have said a few memorable things

How to find classes

This is the 3rd part of my trilogy of blogs on classes and code quality in plugins, the previous two parts are

  1. Are your CRM plugins creating technical debt?
  2. Are CRM Developers are afraid of creating classes?

I have written an increasing number of articles focusing on the quality and design of code, which you can find Hosk’s CRM Developer Articles

To summarise the first blog discusses the effects of creating plugins and putting the code into the plugin.

  • Complex code
  • Hard to read
  • No code reuse
  • Difficult to debug
  • Writing unit tests is hard so most CRM developers don’t bother
  • Creates duplicate code

The second blog post discusses the benefits of creating classes and using abstractions, it allows the developer to manage the effects of change whilst cr

The role of classes

  • Removes duplicate code
  • Modelling real world and abstract ideas
  • Reduces complexity
  • Manages the effects of change
  • Information hiding
  • Create reusable code

The benefits of classes

  • The code is created from many simple classes and methods
  • The code is easy to unit test
  • Well designed classes have minimal dependencies
  • Well designed classes should be able to be reused
  • Classes and method can make the code easier to understand
  • Good abstractions can be used in different projects

You should now be convinced creating classes is the way to go, so how do you find classes

Finding classes

The benefits of creating classes have been outlined above but finding classes and abstractions can be tricky.  Numerous times I have created some initial classes only to find my one class could then be broken into two or three separate classes.

The design of code emerges overtime with unit tests allowing developers to change the code and test it still works.  Development tools can help refactor the code but there is an overhead to changing existing code and tests.

The earlier you can successfully identify classes/abstractions the less time you can spend refactoring your code, so it’s worth improving the methods you use to find classes.

There are some common methods to help developers find classes which I will outline below.

NOUNS = Class, Verbs = Methods

CRM developers usually get a requirements document/functional spec.  It’s good practise to create a use case document to see what steps the end user will go through using the functionality (This will find the different paths through the customization).

The requirements document/use case can be used to find nouns and verbs to help you creates classes and methods.   Nouns give you the classes and Verbs give you the methods.

Nouns – Person/Place/Things
Verbs – Methods/Behavior/action

Using the nouns/verbs method gives you a good start identifying classes but it’s far from fool proof and will miss some classes and create duplicates.

When using this method be aware classes are not always specified as nouns, you may need to look a bit harder.

The nouns/verb method of finding classes and methods is a good start point for finding classes/methods.  When using the process keep in mind you are trying to find abstractions and common functionality in the requirements, design is an iterative process which involves understanding the problem and solution, uncovering more details as you go.

It’s common in use case to use different nouns whilst referring to the same abstraction, so you will find duplicate nouns and part of the process will involve getting rid of duplicates and merging some of the nouns together.

Code Complete 2 gives a clear definition of what an abstraction is

abstraction is the ability to view a complex operation in a simplified form.  A class interface provides an abstraction of the implementation that’s hidden behind the interface

A good way to think about classes as an interface, methods are the actions performed.  Inside a class you have hidden variables.

Finding classes, designing the methods before you start coding helps give a developer a more holistic top down view of the design.  Once a developer starts coding the perspective tends to shift more towards a bottom up approach of the functionality required.

Relationships

After identifing a list of potential classes a good method to find the relationships between those classes is to do a quick Conceptual object of those classes

Object-modeling technique

This helps to identify the interactions between classes, the goal of this task is to highlight any missing classes.

This will show you the behaviour of the classes and what classes will interact with other.  Some of these behaviours will have been found when you looked at the adjectives in the use case.

Responsibilities

It’s interesting to think about the responsibilities your classes are going to have, which class is responsible for certain data

Responsibilities can be

  • Knowledge/state an object maintains
  • Actions/methods an object will perform
  • Services/functionality provided by an object

It can be useful to CRC models

CRC models shows the Colloborators and Responsiblities of a class, below is a useful video

https://www.youtube.com/watch?v=5IpsMwxL37k&list=PLqlI1RpjIS59ziAx7YBqQ0rtyAcpgdsjm&index=25

Find Common Functionality

Classes are also in common functionality and actions used by other classes.

It can help to create class diagrams to see the classes and the interactions between classes.  This can help you find missing classes.

The next stage is create the classes, code and unit tests.  Once the code is working you can think about refactoring/tidying the code and thinking about apply SOLID principles

A good way of finding 2 or more classes within one class is to check the class is focused and doing one thing e.g. The Single Responsibility principle.

A quick way to check if a class is doing more than one thing is the name of the class.  The class should clearly describe what it is/what it does.  Badly named classes often are badly named because they are doing more than one thing.

Actions, manager, Super

Class smells

Here is a list of class smells which often indicate the class is doing to much and could be split into more separate classes

  • Difficult to name the class?  This is usually a sign the class is doing more than one thing
  • Cohesive.  Are all class variables used by most methods, do some methods not use certain variables.  A lack of cohesion is usually a sign a class can be broken out.
  • To many methods.  A high number of methods usually means high complexity, indicating the class is a candidate for refactoring to simplify the code
  • Method length (in lines) – a class bigger than 200 or 300 hundred lines is to big

When checking classes you are often checking for cohesion and if the class can be broken into smaller more cohesive classes.

Cohesion when used to describe design can confuse some readers, so here is wiki’s definition of cohesion

In computer programming, cohesion refers to the degree to which the elements of a module belong together.  Thus, it is a measure of how strongly related each piece of functionality expressed by the source code of a software module is.

Cohesion is the concept all the variables and methods in the class fitting together under the name and purpose of the class.  A class should have a single responsibility, a single purpose.  If a class has more than one purpose then it should be split up.

Example

Here is a quick example

ATM Machine

A bank customer must be able to make withdrawals from the ATM machine using their card.  The card must be validated before the ATM will give money.

ATM machine will check the user has at least the amount of money to be withdrawn in the account.

The bank customer can make a balance enquiry.

Nouns

  • Customer
  • ATM Machine
  • Card
  • money

verbs

  • withdrawn
  • check
  • validated

Further reading

OOSC-2: HOW TO FIND THE CLASSES

From the awesome Bertrand Meyer.  I found the article above very useful

Are CRM Developers are afraid of creating classes?

I have seen lots of CRM code and my initial thoughts are CRM developers don’t seem to create many classes or spend much time designing their code.  In this blog post I will discuss the effects of not creating classes and explain the benefits of classes and abstractions.

Are CRM Developers afraid of creating classes?

The problem seems to be self reinforcing.  Previous CRM projects contain few classes and most of the code exists in the plugin, this sets an unspoken standard which encourages developers to not create classes.

This is a mixture of a safety in numbers/wisdom of crowds approach, it could be seen as consistency and a standard approach to CRM development is good.  Consistency in CRM development helps developers maintain, debug and extend CRM projects.

In the case of putting code in the plugin and not creating classes I think it’s bad practise and every plugin you add creates more technical debt for the CRM project and CRM projects quickly resemble legacy projects with complex CRM customizations

The end result is complex code doing lots of things and impossible to reuse and extremely difficult to work with (maintain, debug, read, etc).

To not use classes and put all or the bulk of the code in the plugin class

  • makes it impossible to reuse code
  • create complex code which does many things
  • creates duplicate code
  • create code which is hard to understand
  • Code is very difficult to test

CRM plugins are often small, focused code but to not create classes or abstractions is to create a code base technical debt.  This debt is paid back when CRM developers take longer to interact with the code in the future.

Plugins with few or no classes results in each developer creating new code every time because it’s impossible to reuse any of the code in the other plugins.

If CRM developers are not creating classes they are creating legacy code and plugins contain monster methods – Hosk

Boy Scout rule

The focus when creating code should be to keep the quality high, test everything and keep code as simple as possible.

When you create plugins or every time you make a code change you make you should leave the code in better state than you found it.  Why you should write code and customizations like a boy scout

Quality of code is fundamental to the long term success of a CRM project and as soon as you lower your coding standards and let in bad code, it will soon spread Bad code is like a virus, don’t get infected

What is the role of Classes in programming

I advocate no code logic should be added to the plugin class except a call to a class passing in the entity, IOrganisationService, ITracing.

Putting logic in a plugin creates complex code, which is difficult to unit test but there are other reasons to create classes which are listed below

No Duplicate code

Duplicate code is one of the worst code smells and it has multiple bad side effects

  • More code = more potential bugs
  • duplicate code = bug fixing can result in multiple fixes
  • bug fix one set = miss out changing duplicate code, which one is right?

When ever you find duplicate code or are about to create duplicate code, take the opportunity to find the common behaviour and abstract it into a class.  This will enable you to reuse this single piece of code in many places.

Using classes and functions is the primary weapon against duplicate code because you are logically sorting code in logical class/method, which will allow developers to easily find and use it.

Modelling real world and abstract ideas

Classes allow you to model real world objects (account) and abstract concepts (printing, validating).  The benefit is you can split up the code into logical abstractions which give clarity to the intent of the code.

CRM out of the box models plenty of real world objects

  • Accounts
  • Contacts
  • Opportunities
  • Phone Calls

Abstract classes

  • Security role
  • Solution
  • Behaviours

You can create classes to model behaviours, this could be things like validating, printing, logging.  These behaviours can be use in composition and used in multiple classes.  The benefit of modelling behaviours is reuse

  • Create abstract objects
  • Create real world objects

Reduce complexity

Classes reduce complexity by splitting code into abstract or logical sections.  The term abstract can be confusing, instead replace it with logical groups.  Splitting code into logical groups organises the code into smaller/reusable sections.

Breaking the code into classes creates cohesive code and reducing dependencies between classes.

Creating well named classes with well named methods reduces complexity and makes the code using those methods and classes easier to read/understand.

Creating classes and methods allows you to create descriptive methods, e.g. call the a print method is easier to understand than reading all the lines of code needed to print.  At a high level you might not need to know all the details of printing.

Manage the effect of change

Classes help reduce the effects of change by removing dependencies between classes (assuming the classes are well designed).  Using abstract classes can remove the effects of change on the code using the abstract classes.

Well designed code can make it easy to add new types by encapsulating what varies and programming to interfaces.  Adding a new type should not effect the other types or the code using the abstract class.

Managing the effects of change can reduce dependences and stop changes in code unexpectedly breaking other parts of the system.  You could rename this to limiting the effects of change by reducing the ripple effect change has on badly designed code.

Information hiding

Read my blog post Good coding practices – Information hiding

hold data instead of lots of parameters

You can structure classes to hold the data instead of passing lots of variables between methods.  This makes the code easier to understand and interact with.

Create reusable code

Many CRM projects I have worked on/inspected have had almost no code reuse partly due to the lack of classes created.  Part of the reason is attitude, CRM developers don’t view creating reusable code as a priority.

CRM organised internal entities to make it easier to understand how it works.  If we take security roles as an example.

The security role entity contains the main privileges which have a value of TRUE or FALSE and one of the four access levels Global, Business Child, Business unit, user.

Every time we add a new entity, we can set privileges for Create, Read, Write, Delete, Append, Append To, Assign, Share.

Whilst thinking about the example above I would except Privilege to be a separate class but we can see understanding the data in this structure is easier.

The benefits of designing classes 

The clean coder has a good change on classes which talks about change isolating change

Needs will change, therefore code will change. We learned in OO 101 that there are concrete classes, which contain implementation details (code), and abstract classes, which
represent concepts only. A client class depending upon concrete details is at risk when those details change. We can introduce interfaces and abstract classes to help isolate the impact of those details.

Abstraction and modularity allows developers to work on separate parts of a system without having a detailed knowledge of the whole system.

Plugins allow developers to create new plugins without affecting other plugins.  The crm dev needs to check there are no other plugins being triggered on the same entity.  Good design of the code is based on on the plugin interface and not the concrete class e.g. your plugin.

Well designed classes have many benefits

  • The code is created from many simple classes and methods
  • The code is easy to unit test
  • Well designed classes have minimal dependencies
  • Well designed classes should be able to be reused
  • Classes and method can make the code easier to understand
  • Good abstractions can be used in different projects

Coding to an interface

The benefits of coding to an interface and using classes behind the interface is you limit the effects of change behind the interface.

You can add new types behind the interface without affecting any of the code which uses the interface.

A quick example is routing records to different users or teams, for this you could create an interface called Route and then concrete classes will contain the routing details and default value of the users/teams.

Route – Interface

  • RouteToTeam
    • RouteToDefaultTeam
    • RouteToSalesTeam
    • RouteToMarketingTeam
  • RouteToUser
    • RouteToSalesManager
    • RouteToCaseManager

The benefits of coding to an interface and using classes

  1. Any code using the Route interface will be unaware of what specific type of route they are using.
  2. The code calling the interface has no knowledge of what objects, variables are used to route, it calls the Route interface methods
  3. Its easy to add new Routes which will involve changing minimal amount of code
  4. The code using the Interface is decoupled from the concrete classes
  5. The effects of change are restrained by the interface
  6. Easy to test
  7. Selecting the type can be done dynamically at runtime

Dependency Inversion Principle (DIP)

Reading about the Dependency Inversion Principle (DIP) helped me understand abstractions and the benefits of using them.  To remind you what DIP is

Depend on abstractions, not on concretions.

Wiki adds two more points to help understand

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should depend on abstractions.

I highly recommend you read Uncle Bobs article The Dependency Inversion Principle, where he explains it a lot better than me.

This article DIP in the Wild has a good example of using DIP which helps understand  the concept and it’s usage in developer life.

Abstract ideas can be tricky to understand, to make this easier to understand think of black boxes.

Black boxes are code which works but the user of the black box doesn’t know how the code works inside the black box.  The internal code can change but the consumers of the black box wouldn’t know.

Change has been isolated inside the black box, Interfaces and abstract classes operate as black boxes hiding the change behind them.   Any code which interacts with an interface/abstract class won’t need to change if the internal workings behind the interfaces/abstract classes change.

A good example is using the CRM SDK to interact with the CRM database.  Microsoft can change how the internal workings of the CRM SDK change and can change the CRM database structure (in CRM 2015 they removed CRM database extension table).

Microsoft removed a whole table but CRM developers who used the SDK wouldn’t have noticed any difference (I didn’t notice) but those who developed code/reports directly against the CRM table would suddenly find their code/reports no longer worked when they upgraded to CRM 2015.

The next blog in the series is how to find Classes

CRM 2013 – Understanding Auditing, Tips, Tricks and Gotchas

I got asked this question today about auditing and some dodgy values, which lead me to look at auditing in CRM.

If you want a quick overview of auditing read this article CRM 2013 – Quick Overview of Auditing

A very quick recap, Auditing can be set at three levels

  • Global
  • Entity
  • Field

The global setting turns auditing on/off.  You can then set auditing on/off for individual entities and individual fields.

You can audit all fields apart from a few system ones.

Funny Looking Icon

Looking at the audit logs I could see an odd icon in the new value column, it looked a bit like a broken basket or maybe a small robot from star wars (image taken from this forum post – MS Dynamics CRM: Audit history shows icons instead of values

 

This cause of this icon is because auditing has been stopped and started again either for the entity or the fields.

For reasons I don’t quite understand when we import a managed solution it often seems to turn auditing off.  I’m guessing this is a CRM 2013 bug of some kind but I can see in the audit logs the message

Entity audit stopped

What seems to happen when we import a managed solution in CRM 2013 SP1 it’s temporarily turning off auditing.

The behaviour is discussed in this forum post

CRM 2011: when auditing is turned off, why do existing Audit records lose “New Value”?

This excellent blog post explained the issue in more detail

A minimalist approach to Managed Solutions in CRM

Auditing (and some other fields) is a checkbox which is either ticked on/off and this value is recorded in your managed solution.  I’m not 100 percent sure imported a managed solution effects the auditing, it doesn’t make sense to import auditing settings because the settings can be changed by users and would be overwritten each time you imported your managed solution.

Something odd happens when we import a managed solution but as yet I’m not sure what it is, if it’s turning fields on or off or if it’s just turning auditing on and off.

How Auditing works

The mighty Scott Durow explained how Auditing data is stored in CRM in this forum post CRM 2011 – Reporting on Audits

2) The Audit view only provides you easy access to the transaction details (user, record, change type, date etc) – to get the attribute change data, you must ‘unpack’ the ‘ChangeData’ field using the ‘AttributeMask’ field. The ChangeData is a ~ separated list of *previous* values. The Attribute Mask is a comma separated list of attribute numbers (as defined by the ColumnNumber field of the [MetadataSchema].[Attribute] table). The difficult bit is that although you can get the ‘previous value’ by parsing these fields, to get the ‘new value’ you must get the next audit entry for the particular record or if there is no next audit entry, you must get the values that are currently stored in the Entity Record. Further more, if it references option set values, you need to lookup the option set value that was valid on that date, and any entity references you will need to lookup the display name since the values only give you the type and id. The SDK Webservices does all this hard work in code rather through SQL and so it will be the easiest to use, however, it isn’t optimized for reporting.

 

To take the relevant parts out

Audit table’s only stored the previously changed value

The current value/new value of a record has to be retrieved from the next audit log or the current field value.

So it seems the audit views we use are a mixture of audit records, mixed in with the current field value, well packaged so we think all the information is in the audit log.

This is a problem for reports but if you retrieve audit records via the CRM SDK it gets you the all the data, another reason to use CRM SDK rather than direct SQL queries in code.

Can’t view Audit logs

There are some security roles associated with auditing and if you can’t view the audit logs you need to get some audit security privileges.

View Audit History
View Audit Summary
View Audit Partitions
Delete Audit Partitions

View Audit History is needed to view the audit history for individual entities.

View Audit Summary is needed to view the audit summary page in the auditing area.

The audit partition security roles are to do with viewing and tidying up the partitions, which is to do with tidying audit logs up and removing some auditing data which is old.

This blog posts walks you through setting up your audit privileges

Enabling Viewing of CRM Audit Records

Be aware field level security fields cannot be audited according to the CRM SDK article – Field security entities

Field level security applies to everything

It applies to all components, such as the Microsoft Dynamics CRM SDK, reports, search, offline, filtered views, auditing, and duplicate detection. For this release, field security can be applied to both custom fields and many out-of-box (OOB) fields.

For a run through of field level security go to this blog post CRM 2013 – How to set up Field Level Security

 

Auditing User access

Auditing allows you to audit when users have logged on to CRM, CRM SDK Audit Access Link

There are a couple of interesting things I learnt from the CRM SDK article

The frequency of auditing user access can be read or set using the Organization.UserAccessAuditingInterval attribute. The default attribute value of 4 indicates user access is audited once every 4 hours.

Which makes me wonder how exactly it audits user access?

The other interesting part of user auditing is it can tell how the user logged on to CRM

  • AuditAction.UserAccessviaWeb
  • AuditAction.UserAccessviaWebServices

UserAccessviaWeb indicates the user accessed CRM via Outlook client or Web Application

UserAccessViaWebServices indicates access via  web services call to the CRM SDK.

The blog post from Microsoft support talks about auditing in more detail

Dynamics CRM Audit & User Access Data

I did work out an SQL query which gets last time a user logged onto CRM, The article above has a similar query

CRM 2011 – How to get the Last Login Date and Time of a CRM Instance

Audit reporting

Creating a report for audit logs can be tricky because it has to be an SQL report because there are no auditing entities you can access.

Auditing doesn’t have a filtered view which makes a bit harder with regards to security/privileges.  Filtered views are useful because they check the security/privildges the person running the report has, only showing the records they can see.

No filtered view means anyone viewing the audit report could be viewing records and fields they shouldn’t be able to see.

This does mean it’s not possible to create audit reports for CRM online.

I found a couple of examples of audit reports

DYNAMICS CRM 2011 AUDIT REPORT IN SSRS

Dynamic CRM 2011/2013 Audit Report in SSRS

CRM 2011 & CRM 2013–Usage Audit Report (On-Premise Deployment)

Audit CRM SDK Code examples

There are a couple of CRM SDK samples which show you how to get audit information programmatically.

Sample: Audit entity data changes

Sample: Audit user access

Recover your deleted CRM data and recreate them using CRM API

If you have to write an audit report for a CRM online, you could use the CRM SDK to get the data but it seems like hard work to me and probably time to tell the end user it’s not worth the effort.

 

 

 

CRM 2013 – Javascript null setting oddity

I had an odd error where I was trying to null a lookup field in Javascript in CRM 2013 Service SP1.

When the user changed a lookup field, I wanted to blank out a few fields to make them select those fields again.  The fields being nulled were dependant on selection of the first lookup field and the options and values they could pick changed.

It’s good practise to reduce the number of choices users have by filtering out values in option sets and lookups, hiding/showing fields.  This makes the forms more cohesive, less noise for the end users.  Read more about CRM Form design in the article below

Good CRM design should not make users think

The initial code was in a function and looked like this

        if (Xrm.Page.getAttribute("field1").getValue() != null) {
            Xrm.Page.getAttribute("field1").setValue(null);
        }


        if (Xrm.Page.getAttribute("field2").getValue() != null) {
            Xrm.Page.getAttribute("field2").setValue(null);
        }
        

Oddly field1 was correctly set to null but field2 refused to be set to null.

To add to the annoyance of not setting the field to null, the not nulling triggered the OnChange event for the lookup which set other values on the previous not nullable value!!!

This made me angry

Stepping through

When bug fixing the goal is understand exactly what is happening, once you understand what is happening it might be possible to work out why or work around it.  There is a big difference between

  • Knowing what is happening
  • Your assumptions about what is happening

Assumptions are dangerous because they can easily be wrong.  When bug fixing don’t assume anything and prove everything.  I have wasted plenty of time with assumptions and investigating the wrong section of code.

I started debugging and stepped through the setting the values to null.  The handy part of debugging JavaScript is the console allows you to integrate the values.

The values on the GUI looked like fields1 and fields2 were both not being set to null.

I debugged and stepped through the code, field2 wasn’t being set to null but the OnChange event was running for field2 which was setting field1 and field2 to the values based on the previous field2 value.

One change at a time

One of the golden rules when debugging a problem is to change one thing at a time, monitor the effects of the change.  This rule is particularly inportant if the change is a configuration change which will be changed on multiple environments (DEV, TEST, PREPROD, PROD).

When changing values or code, making a solitary change will show you the effects of the one change.  If you change 5 things at once which resolves the problem, you don’t know what change has fixed the problem.  In the multiple change scenario you would either need to go back and change one variable at a time or make all the changes in all the environments.

When making changes to code/config it’s good practise to minimise the changes, which minimises the potential unknown effects of these changes and reduces bugs coming from these changes less likely.

I tried

  • removing field1 change
  • swapping the order, changing field2 before field1
  • double checking javascript
  • Asking fellow CRM developers

Asking fellow CRM developers did bring a few mumbles of maybe having seen something like it before but no one could remember what is was or what they did (if only they wrote a blog post about it!!)

None of the other changes did much.

To the Internet

 

Searching the internet didn’t bring up anything directly relevant (how often does that happen!), it did lead me to this page

Javascript, onChange events no longer work on an empty field

This wasn’t the problem I was experiencing

I just noticed that if you have a form field that triggers a Javascript function on the onChange event it no longer triggers the function if you clear the field, but ONLY when you change the field data. For instance; if you have a Name field populated with a name, and you remove the name – the function isn’t triggered. It’s left empty. You have to change the text inside the field.

 

The problem being talked about here is setting required fields to null didn’t trigger the onchange.  I had this reverse of this problem I was setting field2 to null, it wasn’t setting but triggering the OnChange, which means Microsoft fixed the problem report (the forum posts were Feb 2014).

The forum post go me thinking, lets change the field requirements and see what happens.

Setting field requirements using Javascript

Fields have three levels of requirements

  • none
  • required
  • recommended

For some reason accessing these programmatically seems quite different from setting/adjusting them using the GUI.  Looking at the list what is the point of recommended, it should be required or none.  Why you would want to change a field to have a requirement level of recommend?

The code is string based, which seems a little odd and prone to syntax errors.  To find all the Javascript methods use this page on the CRM SDK

Xrm.Page.data.entity attribute (client-side reference)

Here is an example using the trusty field2

  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“none”);
  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“required”);
  • Xrm.Page.data.entity.attributes.get(“field2”).setRequiredLevel(“recommended”);

I changed my code to set the required level to none, set field2 to null and then reset the required level to required.

//I had to set required level to none because assign null wasn't working, might be fixed in future roll ups
	if (Xrm.Page.getAttribute("field1").getValue() != null) {
            Xrm.Page.getAttribute("field1").setValue(null);
        }

        Xrm.Page.data.entity.attributes.get("field2").setRequiredLevel("none");
        if (Xrm.Page.getAttribute("field2").getValue() != null) {
            Xrm.Page.getAttribute("field2").setValue(null);
        }
        Xrm.Page.data.entity.attributes.get("field2").setRequiredLevel("required");

Leave a comment

If you have written some unusual code as a work round for a limitation in design or a known bug, it’s good practise to leave a comment explaining to other developers (and maybe your future self) why you have put the code.

Reasons why you should comment unusual code

  • A developer could easily delete the code without realising what is meant to do
  • It could be confusing for other developers to read and understand
  • A rollup/service patch might fix the code and it could be safely removed
  • The developer reading the code might know the solution to this problem
  • It’s good practise