When you first begin working with the Dynamics CRM SDK, there is a lot of specific terminology, concepts and methods that need to be grasped firmly. The importance of this is twofold: it enables you to judge the best approach when developing your bespoke solution that fits in within CRM and allows you to gain a very good understanding of the underlying CRM platform. The terms “early-bound” and “late-bound” are, arguably, the most important of these terms/concepts to fully understand, so it is useful to first explain what each of these refer to and the benefits & drawbacks of each, before we get into this weeks blog post properly:

Early Bound

Early bound refers to when you are using a generated class file to access all of the customization data for your CRM within your code. The SDK Bin folder contains an executable file called CrmSvcUtil, which can be used to generate this file. There is a great MSDN article that goes through the steps involved as part of this; once you’ve got the file, simply add it into your Visual Studio project and Intellisense will automatically detect your entity, relationship etc. names! Suffice to say, going down the early bound route can significantly ease your development work, as your strongly-typed class file will contain everything you would require regarding your CRM entities. As such, you will be able to ensure that your code is accessing the correct attributes, relationships and other objects within CRM at all times.

Given that it makes a developers jobs ten times easier, why wouldn’t you want to use Early Bound in your code all the time? Your strongly-typed class file is essentially a snapshot of your current CRM instance, at the date and time when you ran the CrmSvcUtil. As soon as someone makes a change within CRM, your class file may no longer be correct and you may encounter major problems when executing your code against your target CRM environment. This problem can also be compounded if you are developing an ISV solution that is executed against a varied number of environments, where there could be entities/attributes present that your code has no reasonable way to anticipate; in this case, it becomes absolutely essential for you to consider using late-binding instead within your code.

Late Bound

Late binding is the exact opposite of early binding. To access your CRM entities via the late-bound route, you use the Microsoft.Xrm.Sdk.Entity class to declare the new or existing entity that you wish to work with within your code. Typically, you will need to have your CRM Solution open in front of you as part of using late-binding, so that you can reference the logical names of your entities & attributes. You are therefore not “restricted” in the same way that you are with early-binding – you can declare any possible logical name for your CRM objects that you want, which, as mentioned already, is essential if you are blind to the CRM instance(s) in question. There is also a performance benefit to using the late-bound Entiy class, depending on the number of records your code is working with. According to the following Microsoft best practice article:

In addition, if your custom code works with thousands of entity records, use of the Entity class results in slightly better performance than the early-bound entity types.

One of the major drawbacks of using late binding is the increased chance of errors in your code, as you will need to ensure that your logical names are typed correctly; any such mistakes, as we will demonstrate further below, may cause your code to fall over straight away and lead to hours of frustrating debugging in order to resolve.

Now, to the heart of the matter…

I recently had a conversation with a developer colleague, who gave me some advice in relation to some plugin code I had written. Within my code, I had attempted to access the value of a Single Line of Text Entity attribute, using late-bound classes, in the following manner:

string myAttribute = myEntity["myattribute"].ToString();

They recommended instead that I look at using the GetAttributeValue method instead, which in this case, would be expressed in the following manner

string myAttribute = myEntity.GetAttributeValue<string>("myattribute");

My colleague elaborated on a few reasons why this approach is preferential (which I will discuss at the end of this post), but I was interested in dissecting this further myself, to see how it works in practice. In my test CRM instance, I created a plugin for the Contact entity, that would fire on the Post-Operation event of the Update Message, for the First Name field. The plugin very simply accesses the value of this field using the two different approaches, which can be done like so:

//First, initialize your Contact entity

Entity contact = (Entity)context.InputParameters["Target"];

//Now we can access our attributes - the first way is like this...

string contactField1 = contact["firstname"].ToString();

//The second way...

string contactField2 = contact.GetAttributeValue<string>("firstname");

When we play back the plugin execution in Visual Studio, we can see that this returns our expected values. In this particular example, we have attempted to rename our “Homer Simpson” Contact record to “Bart Simpson”:

1 2

 

So, at this stage, there does not appear to be a clear benefit of using one snippet over the other. But what happens if we attempt to access an attribute that does not exist? We can test this by adding the following lines of code to our plugin:

//Next, we test what happens if there is a typo - first, we try GetAttributeValue

string contactField3 = contact.GetAttributeValue<string>("thiswillerror");

//Then, the alternate way

string contactField4 = contact["thiswillerror"].ToString();

When we use our GetAttributeValue approach, our contactField3 returns a null value… :

3

Whereas our contactField4 instantly causes an error, which would also be returned to the user within CRM…

4

Where possible, we always want to try and prevent an Exception from being passed back to CRM and build in the appropriate error handling within our code, and this was one of the benefits that my colleague highlighted in this approach. So, for example, you can build in an if…else statement as part of the above example that checks whether the GetAttributeValue is Null and then perform the appropriate action, depending on the result. Having spent time working with the method more closely, I can also now see a clear benefit in relation to code readability – it is definitely more obvious what GetAttributeValue is doing within a code example, compared with the alternative approach, as well as making it obvious what the data type of the attribute is within CRM. Keep in mind however that you still need to ensure that you are using your correct Data Types, both when creating your C# variables and referencing your CRM attributes – for example, you cannot return the contactid field as a string, as this will generate an InvalidCastException.

To finish off, I would invite you to look through this excellent article from Guido Preite, that takes a deep-dive look at the GetAttributeValue method in a variety of different scenarios. Definitely one to save to your bookmarks 🙂

One of the nice things about working with lookup fields on entity forms is the ability to filter the results programmatically via a form level JScript function. The steps for doing this, thankfully, are rather straightforward:

  1. Prepare a FetchXML filter snippet that applies the type of filtering you want to perform. This can either be written manually, or you can build your filter within Advanced Find, download the FetchXML and then copy + paste the <filter>…</filter> node.
  2. Access the control using the Xrm.Page.getControl object, and then use the addCustomFilter method to apply the filter
  3. Finally, setup your function to fire on the OnLoad event, using the addPreSearch method to actually apply the filter to the lookup control.

If you are still scratching your head at the above, then fortunately there is an MSDN article on the subject which provides further guidance, including a handy example snippet that you can modify and apply straight to your CRM instance. What I like most about this method is that its application is simple, but its potential is quite huge. Utilising conditional logic within your Jscript function means that you could potentially filter results based on values on the form, via a web service request to another CRM record or based on the value in an external CRM/ERP system. Used correctly and prudently, it can help to make form level data inputting much more easier and context sensitive.

CRM has a number of special field types that are reserved for certain system entities. One example is the Customer Data Type field. This is, in essence, a special kind of lookup control that spans two entities – Account & Contact. System customisers are able to create additional fields with this data type, but are unable to create a customer lookup control that spans across 2 entities of choice. This is a real shame, as I think this feature would be really welcome and be widely applicable to a number of different business scenarios.

I was recently working with this particular field on the Contact entity in order to meet a specific requirement as part of a solution – for only certain Account records to appear and for no Contact records to be made available to select. One potential work-around would be to just create a new 1:N relationship between Account:Contact, but this seems rather unnecessary when there is already a relationship in place that could be modified slightly in order to suit requirements. I was therefore interested in finding out whether the addCustomFilter/addPresearch methods could be utilised in this case. After a small, yet sustained, period of severe head-banging, I was able to get this working; although the solution could be argued as being less than ideal.

For the above requirement, lets assume we have a custom field on our Account entity – Company Type – which we are using to indicate what type of UK company an Account is:

4

Once created, we then populate our CRM sample Account records with the value of ‘Limited Company (Ltd.) and run a quick Advanced Find to confirm they return OK:

7

8

Now, for this example, we want to apply a very basic filter on the Customer field on our Contact entity to only show Account records that equal ‘Limited Company (Ltd.)’. Here is our “first attempt” JScript function(s) to achieve this:

function onLoad() {

    Xrm.Page.getControl("parentcustomerid").addPreSearch(modifyCustomerLookupField);

}


function modifyCustomerLookupField() {

	fetchXML = "<filter type='and'><condition attribute='jg_companytype' operator='eq' value='140250000' /></filter>";
	Xrm.Page.getControl("parentcustomerid").addCustomFilter(fetchXML);


}

After creating a JScript Library, adding it to a form, calling the onLoad() function as part of the OnLoad event and, finally (whew!), pressing the magnifying class on the control, we immediately get an error message:

1

Here’s the error message:

5

As a next step, to try and resolve this, I remembered within the FetchXml <filter>…</filter> node, you can specify the name of the entity that you want to filter on. This is typically required when you are using <link-entity> in order to join together multiple records. So I modified my JScript function to include the entity name within the fetchXML filter:

function onLoad() {

    Xrm.Page.getControl("parentcustomerid").addPreSearch(modifyCustomerLookupField);

}


function modifyCustomerLookupField() {

	fetchXML = "<filter type='and'><condition entityname='account' attribute='jg_companytype' operator='eq' value='140250000' /></filter>";
	Xrm.Page.getControl("parentcustomerid").addCustomFilter(fetchXML);


}

With fingers crossed, I then tried again…but still got an error message, but a slightly different one. Some progress at least!

2

3

Once my head had returned from the desk in front of me, I looked back at the original error message, in particular the fact that the Contact entity does not contain the new field we have on our Account. This is to be expected, but is there some way we can “fool” CRM by also having a field with the same name on Contact, but which is not used for anything? Going back into my solution, I created a field with the exact same logical name on the Contact entity, making it clear that this field should not be used. The data type, description etc. does not matter, so long as the logical name is the same as our field above:

6

 

Going back to our form and trying again, we see that this looks to have done the trick – our three records are now returning successfully when we use the control! 🙂

9

Another good thing about this is that the custom filter will also apply when the user clicks on ‘Look Up More Records’; although the Contact entity can still be selected, no records will be returned for obvious reasons.

I was glad this was ultimately possible to get working; however, to play devil’s advocate for a few moments, it is worth noting the following if you choose to set this up within your own environment:

  • Simply creating a new 1:N relationship between Account:Contact would be a more straightforward and less technical approach of achieving the above; you should review your requirements carefully and consider whether this approach would satisfy your objectives.
  • By adding form level JScript to this entity, you may start to impact on your form load times, particularly if you have lots of other functions running on the form or if you implement additional logic into your function.
  • It is arguably not best practice to have a field within CRM that is being used in a “hacky” manner, as outlined above. If you are happy to have such a field within your CRM environment, then you will need to ensure that you take a number of steps to clearly label this field and its purpose within the CRM. The last thing you want is for someone to delete it by accident.

If anyone else has found a better or alternative way of achieving the above, please let me know in the comments below!

The ability to implement trace logging within CRM plug-ins has been around since CRM 2011, so it’s something that CRM developers should be well aware of. Writing to the trace log is useful for when a plug-in has failed or hit an exception, as within the ErrorDetails.txt file (available to download from the error message box window) will be a list of everything that has been written to the log, up to that point. One issue with this is, if a user encounters an error and does not choose to download this file, then this file is lost – not so much of an issue if the exception can be re-produced, but this may not always the case.

For those who are now working on CRM Online 2015 Update 1 or CRM 2016, then a new feature has been added which further expands this feature – the Plug-in Trace Log. Now, plug-in exceptions can be configured to write to a new system entity, containing full details of the exception, that can be accessed at any time in order to support retroactive debugging. The introduction of this feature means now is the best time to start using trace logging within your plugins, if you are not already. This weeks blog post will take a look at the feature in more detail, assessing its pros & cons and providing an example of how it works in practice.

So, before we begin, why you would want to implement tracing in the first place?

Using tracing as part of CRM Online deployments makes sense, given that your options from a debugging point of view are restricted compared to an On-Premise Deployment. It is also, potentially, a lot more straightforward then using the Plug-in Registration Tool to debug your plugins after the event, particularly if you do not have ready access to the SDK or to Visual Studio. Tracing is also useful in providing a degree of debugging from within CRM itself, by posting either your own custom error messages or feeding actual error messages through to the tracing service.

Just remember the following…

Writing to the tracing service does add an extra step that your plug-in has to overcome. Not so much of an issue if your plugin is relatively small, but the longer it gets, and more frequent you are writing to the service, means there is a potential performance impact. You should use your best judgement when writing to the service; not every time you do something within the plugin, but where there is a potential for an error to occur. Writing to the tracing log can also have an impact on your CRM storage capacity, something we will take a look at later on in this post.

Now that we have got that out of the way, lets begin by setting up an example plugin! 

To start writing to the Tracing service depends on how you are implementing your plugin. If you have used the Visual Studio template, then simply use this line of code within the “TODO: Implement your custom Plug-In business logic.” section:

ITracingService tracingService = localContext.TracingService;

Otherwise, you will need to ensure that your plugin is calling the IServiceProvider, and then use a slightly longer code snippet to implement the service. An example of the code that you’d need to use to setup this is as follows:

using System;

//Be sure to add references to Microsoft.Xrm.Sdk in order to use this namespace!

using Microsoft.Xrm.Sdk;

namespace MyPluginProject
{
    public class MyPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            //Extract the tracing service for use in debugging sandboxed plug-ins.
            
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
        }
    }
}

Once you’ve implemented the ITracingService within your code, you can then write to Trace Log at any time in your code using the following snippet:

tracingService.Trace("Insert your text here...");

Activating Tracing

Even though we have configured our plugin for tracing, this does not automatically mean that our plugin will start writing to the log. First, we must configure the Plug-in and custom workflow activity tracing setting within the System Settings page:

TracingSettings

You have three options that you can set:

  • Off – Nothing will be written to the trace log, even if the plugin encounters an exception.
  • Exception – When the plugin hits an exception, then a trace will be written to the log.
  • All – Whenever the plugin is executed and the trace log is called, then a trace log record will be created. This is equivalent to Verbose logging.

As mentioned earlier, individual records will be written to CRM whenever the tracing service is called. It is therefore recommended only to turn on ‘All’ for temporary periods; leaving it on for ‘Exception’ may be useful when attempting to initially diagnose plugin errors. Review the amount of storage available to you on your CRM Online/On-Premise deployment in order to determine the best course of action.

Tracing in Practice

Now that we’ve configured tracing on our CRM and we know how to use the Tracing, lets take a look at an example plugin. The below plugin will be set to fire on the Post-Operation event of the Update message on the Account entity. It will create a new contact record, associate this Contact record to the Account and then populate the Description field on the Contact with some information from the Account record:

protected void ExecutePostAccountUpdate(LocalPluginContext localContext)
    {
        if (localContext == null)
        {
            throw new ArgumentNullException("localContext");
        }

        //Extract the tracing service for use in debugging sandboxed plug-ins.

        ITracingService tracingService = localContext.TracingService;
        tracingService.Trace("Implemented tracing service succesfully!");

        // Obtain the execution context from the service provider.

        IPluginExecutionContext context = localContext.PluginExecutionContext;

        // Get a reference to the Organization service.

        IOrganizationService service = localContext.OrganizationService;

        if (context.InputParameters.Contains("Target"))

        {
            //Confirm that Target is actually an Entity

            if (context.InputParameters["Target"] is Entity)

            {
                Guid contactID;
                string phone;

                Entity account = (Entity)context.InputParameters["Target"];
                tracingService.Trace("Succesfully obtained Account record" + account.Id.ToString());

                try

                {
                    tracingService.Trace("Attempting to obtain Phone value...");
                    phone = account["telephone1"].ToString();
                            
                }
                    
                catch(Exception error)

                {
                    tracingService.Trace("Failed to obtain Phone field. Error Details: " + error.ToString());
                    throw new InvalidPluginExecutionException("A problem has occurred. Please press OK to continue using the application.");

                }

                if (phone != "")

                {

                    //Build our contact record to create.

                    Entity contact = new Entity("contact");

                    contact["firstname"] = "Ned";
                    contact["lastname"] = "Flanders";

                    contact["parentcustomerid"] = new EntityReference("account", account.Id);

                    contact["description"] = "Ned's work number is " + phone + ".";

                    contactID = service.Create(contact);

                    tracingService.Trace("Succesfully created Contact record " + contactID.ToString());

                    tracingService.Trace("Done!");

                }

                else

                {

                    tracingService.Trace("Phone number was empty, Contact record was not created.");

                }
            }
        }
    }

After registering our plugin and with tracing configured for “All” in our CRM instance, we can now see our custom messages are being written to the Trace Log – when we both update the A. Datum Corporation (sample) record Phone field to a new value and when we clear the field value:

Plugin_1

Plugin_2

Plugin_3

Most importantly, we can also see that our test Contact record is being created successfully when we populate the Phone field with data 🙂

 

Plugin_4

Now, to see what happens when an error is invoked, I have modified the code above so that it is expecting a field that doesn’t exist on the Account entity:

Plugin_5

Now, when we attempt to update our Account record, we receive a customised Business Process Error message and window:

Plugin_6

And we can also see that the precise error message has been written to the trace log, at the point we specified:

Plugin_7

Last, but not least, for On-Premise deployments…

One thing to point out is, if you are using On-Premise CRM 2016 (both 8.0 and 8.1), then for some reason the trace log will not work if you do not run you plugin within sandbox isolation mode. I’m not the only one experiencing this, according to this post on the Dynamics CRM Community forum. Switching my test plugin to sandbox isolation resolved this issue. A bit of a strange one, and as Srikanth mentions on the post, it is not clear if this a bug or not.

Conclusions or Wot I Think

Trace logging is one of those things where time and place matter greatly. Implementing them within your code obsessively does not return much benefit, and could actually be detrimental to your CRM deployment. Used prudently and effectively though, they can prove to be incredibly useful. The scenarios where I can see them returning the most benefit is if your plugin is making a call to an external system and, if an error is encountered during this process, you can use the Trace Log to capture and store the external application error message within CRM for further investigation. Trace logging can also prove useful in scenarios where an issue cannot be readily replicated within the system, by outputting error messages and the steps leading up to them within the Trace Log.

In summary, when used in conjunction with other debugging options available to you via the SDK, Trace Logging can be a powerful weapon to add to your arsenal when debugging your code issues in CRM.

Anyone working within the CRM space will have already soaked up the news regarding Dynamics 365. Jujhar Singh’s announcement just a week before WPC 2016 helped to set the stage for Dynamics 365 & AppSource to steal the show as part of the conference, no doubt pleasing Dynamics professionals the world over. This is a major step forward for Microsoft, as they seek to quash the dominance of Salesforce, SAP & Oracle within the CRM/ERP space; having long been the underdog within this sector, Dynamics 365 could be what Microsoft needs to tip the scales in their favour.

So, if you are working with CRM closely at the moment, what does the above announcement mean for you? Is CRM still relevant or is it time to pivot across to some of the new offerings within Dynamics 365? In this week’s blog post, I take a closer look at what has emerged from the above announcement thus far, to see where the future may lie for CRM:

Is CRM now an Enterprise-level product?

At this stage, Microsoft are speaking in very high-level terms in respect to how the Dynamics 365 product will be licensed. But I was interested to see the following slide on show at WPC (picture courtesy of Peter Cutts):

Taking the above at face-value, Microsoft are now classifying CRM as an Enterprise-only product, a potentially concerning development. Some implications of this decision could be:

  • Price rise on all CRM licensing plans as part of Dynamics 365: I think in the short-term, it is incredibly unlikely that we will see a major jump in price (in order to help drive early adoption), but since CRM is now classed as an enterprise level product, it would be very surprising if pricing is not eventually adjusted, in order to take this into account.
  • Rise in minimum license purchase for CRM Online: This is currently set to 5 Professional licenses, whereas the above slide indicates a minimum seat purchase of 20 users. If we assume the same price under Dynamics 365, the minimum monthly cost to start using CRM Online rises up to £810 ex. VAT, which equates to a whopping rise of £607.50 per month! [UPDATE: Since this post, I have had it confirmed that CRM Online minimum seat purchase will not be affected by Dynamics 365. More info can be found here. Big thanks to CRM MVP Jukka Niiranen for pointing this out!]
  • The future of CRM within SMB’s: I am hoping that some further detail will help to clarify the position of CRM within the overall offer, but one of my major concerns at this juncture is the future position of CRM Online within small to medium size businesses. One of the huge benefits of the current structure is that is tailored for both extremes; a major shift of the CRM product towards an enterprise-only approach (i.e. in the sense that the price point precludes any other, smaller organisation from justifying the cost of adopting CRM) could spell the end of CRM within the small business. One would assume that Project ‘Madeira’ would be the alternative offer for SMB’s in this instance; but the challenge would be in convincing these organisations to migrate across to this.

Looking at this another way, Microsoft have promised that the Dynamics 365 offering will be flexible and adaptable for any kind of business. So it may well be the case that we see no major changes to how the CRM Online product is offered, something that I would welcome.

Time to say goodbye to CRM On-Premise?

One of the persistent questions, considering the increased focus on CRM Online in recent years and the Dynamics 365 announcement as a whole, is just where does On-Premise CRM sit in Microsoft’s long-term plans. Some colleagues I have spoken to recently have predicted that Dynamics 365 is the nail in the coffin for CRM On-Premise. I take a slightly more pessimistic view. With many large-scale organisations within the public/private sector still requiring the ability to literally point to a server rack in a data centre and say “This is where our data is stored!”, it will be difficult for Microsoft to convince them to migrate across to the Office 365/Azure platform, when such requirements may prove difficult to match. The UK is currently an excellent case in point, as we are still waiting on the promised arrival of UK based Azure data centres. Until Microsoft are in a position to offer commitments to every country in the world that they have data centres based within the country in question (or, in the case of Europe, within the European Economic Area), CRM On-Premise will continue to have a market for organisations who need specific assurances in regards to data storage and location.

The future of XRM

The XRM framework is a developers skeleton key, in terms of unlocking further potential from CRM and extending it to suit specific business requirements. So does the Dynamics 365 announcement mean that this key is now useless? Microsoft have provided some re-assurance that XRM is not going away anytime soon…

To extend the functionality of individual Dynamics 365 apps, partners may continue to use native application extensibility frameworks built-in to the CRM and the AX platforms.

But they have also indicated that there is a new sheriff in town…

The common data model is a cloud-resident business database, built on years of experience with our enterprise customers. It will come with hundreds of standard business entities spanning both business process (Dynamics 365) and productivity (Office 365). The standardization and consistency of schema enables partners to build innovative applications and to automate business processes spanning the entire business process spectrum with confidence their solutions can be easily deployed and used across Microsoft’s entire customer base.

Source: https://community.dynamics.com/b/msftdynamicsblog/archive/2016/07/06/insights-from-the-engineering-leaders-behind-microsoft-dynamics-365-and-microsoft-appsource

Clearly, the new “common data model” is something that CRM professionals are going to have to familiarise themselves with, as well having a general awareness of the other products sitting within Dynamics 365. One good thing to note, according to this blog post, is that there is some familiar terminology! I potentially see this as a positive step forward, particularly if your organisation is developing ISV solutions that sit within CRM and the constraints of CRM Solutions mean that you cannot leverage the desired functionality from the application.

A Fork in the Road – How Dynamics 365 could lead to CRM Specialist Roles

The Dynamics 365 announcement would also look to confirm that the Sales and Service side of CRM are starting to be treated as separate offerings, within one common environment. We’ve already seen that Microsoft have segregated out the Sales and Service side of CRM into different exams, and also that, when requesting a CRM demo, you can choose to have a Sales or Service focused trial experience. I can foresee a scenario where existing CRM professionals are having to “evolve” into one of three types of roles:

  • CRM Service Specialists
  • CRM Sales Specialists
  • Dynamics 365 Specialists

Without wishing to continue the references to Pokemon much further, we can then see situations where businesses are saying, for example, “CRM Service Specialist, I choose you!” for a particular project. Having focused roles along the lines of the above will undoubtedly lead to greater specialist knowledge of certain aspects of CRM, but could mean that professionals are no longer getting a good look over the garden fence at what’s going on within Dynamics 365 or within CRM itself.

Always Look on the Bright Side: Why Dynamics 365 could be awesome

Dynamics 365 can be seen as yet another gesture of love and attention towards the Dynamics CRM product. CRM has developed in leaps and bounds in recent history; this announcement would appear to be the cherry on the cake, designed to convince organisations across the globe that having CRM within their business can precipitate major benefits and return on investment. Dynamics 365 also gives those working with CRM an excellent excuse to start familiarising themselves with the other products in the Dynamics family. Typically, despite the shared name, these products have stood in distinct isolation from each other. Bringing them together as part of Dynamics 365 will hopefully lead to greater shared knowledge and awareness of what products, such as NAV, can deliver. Finally, the common data model, if designed correctly, could offer a much effective and less restrictive means of configuring CRM to interact with other products/systems.

There will no doubt be more news on Dynamics 365 in the months ahead, culminating with its release as part of Summit 2016 in October. For now, we will have to wait patiently, but I am eager to get my hands on it, as Dynamics 365 will undoubtedly be an important string on the bow of CRM professionals in the years ahead.

I was working within CRM recently, attempting to configure some form level logic in order to display/hide fields, based on certain conditions on the form itself. I went into it rather gung-ho and immediately started writing the following JScript function:

function hideFormFields() 

{

    var myField = Xrm.Page.getAttribute("jg_myfield").getValue();

    if (myField = "Value1") {

        Xrm.Page.getControl("jg_myfieldtohide1").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide2").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide3").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide4").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide5").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide6").setVisible(true);

    }

    else if (myField = "Value2") {

        Xrm.Page.getControl("jg_myfieldtohide1").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide2").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide3").setVisible(true);
        Xrm.Page.getControl("jg_myfieldtohide4").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide5").setVisible(false);
        Xrm.Page.getControl("jg_myfieldtohide6").setVisible(false);

    }
}

I then suddenly thought “Hang on – can’t this be done via a Business Rule instead?”. For CRM Administrators who do not have any previous development skills, Business Rules were a godsend when Dynamics CRM 2013 was first released, having been continually improved since. They essentially enable you to implement conditional logic and actions on your entity forms, without the need of writing a single line of code. Business Rules are, in fact, a form of JScript, utilising many of the capabilities available as part of the XRM framework. As an excellent case in point, we can very easily replicate the above code into a Business Rule, like so:

BusinessRule

There is an important lesson here, that anyone who works extensively within CRM needs to always remember; if it can be done out of the box within CRM, then why would you go to the trouble and effort to write a JScript function? Here are some reasons why CRM Developers should always think twice before typing away on that new form-level JScript function:

Business Rules actually do a lot more than you’d expect

This is something I am guilty of forgetting, and I’m having to train myself to consider this more carefully in future. In the above example, I made the immediate assumption that showing/hiding form fields on a conditional basis was not possible via a Business Rule – how very wrong I was! This seems to underline a general theme with how CRM customisers/developers approach Business Rules, assuming a glass half-empty approach. As of 2016 Update 1, as well as being able to modify a fields visibility, Business Rules can also support the following scenarios:

  • Show Error Message
  • Set Field Value – Fields can be set to match the value of another field, a specific value (including lookups), the result of a formula (Date/Number fields only) or be cleared of data.
  • Set Business Requirement.
  • Set Default Value – Fields can be set to match the value of another fields, a specific value (including lookups) or as the result of a formula (Date/Number fields only).
  • Lock or unlock field

What emerges, when combined with the conditional logic builder, is a means of utilising some of the most frequently used methods available to you via the SDK. And we can also hope and anticipate that as part of future releases of CRM, this list will be expanded on further.

Business Rules are supported, whereas your JScript may not be

To summarise another way, although you can do lots of things via Jscript within CRM, that doesn’t mean that you should. One thing I have observed with those who work with CRM, but have had more of a developer background, is that there is tendency to utilise methods/code which is not officially supported by Microsoft within CRM. Looking around the CRM community, and you often see that an unsupported solution is provided to a specific requirement, but often with no warning label attached to stress what it is doing. A good example of something which is unsupported is manipulating the Document Model Object (DOM) of the current page. Just because it works now doesn’t mean it will in the future, potentially causing major problems for your CRM deployment. If you are ever in doubt, be sure to review the supported extensions article on MSDN for CRM, and always think twice before you start using that nice bit of code you find on a Google search.

Your JScript may cause problems for end users

So your JScript is supported – great! But that doesn’t necessarily mean it’s going to work well from an end users perspective. If your JScript code, for example, does not provide a sufficient level of error handling, your end users could end up receiving error messages frequently. Or perhaps consider a scenario where your code is handling your errors well and outputting them correctly for potential debugging; this can lead to more lines of code that are unnecessary, and cause an impact when running the application on certain machines/browsers. With Business Rules, you don’t have to worry about addressing that careful balancing act between form loading times versus JScript library sizes. And, you can be assured that the CRM application as a whole will be able to handle your custom logic without affecting the performance of your deployment.

Jscript should have a time, place and bespoke requirement

What I mean by this is that JScript should only really begin to factor in when you are dealing with very specific, business requirements that the application “as-is” has no means of satisfying. An example of this is if you need to provide specific data validation to a field (such as a telephone number or bank sort code number). The only way this is ever going to be possible is via some kind of Regular Expression (RegEx) validation, which can only be performed via JScript. As one the key takeaways from this blog post, I would stress that you should always first attempt to build a Business Rule that is designed to meet the requirement that you are looking for, utilising other out of the box elements where appropriate (fields, workflows etc.). When it starts to become pretty obvious that a Business Rule is not going to cut it, then you can “give yourself permission” to start writing a JScript function 🙂

A “No Code First” approach should always prevail

I was recently introduced to this simple concept, but it is one that got me thinking and re-evaluating many of my previous solutions that I have built within CRM and elsewhere. When attempting to provide a potential solution to a requirement within CRM, you should try and put forward two solutions (where possible): a solution that can be achieved using out of the box functionality and one that requires bespoke coding to resolve. It may be that the first solution requires considerable time to build within CRM, but doing it this way could mean your solution is a lot more readable and understandable for those going into the system in future. By comparison, your 3-6 lines of code could prove to be virtually indecipherable.

So, in conclusion, can you guess what your new “Rule” should be moving forward?

Going back to my earlier example of your CRM Developer, AKA Former Application Developer, person, you can anticipate that they will have a very good knowledge of what CRM is capable from an SDK point of view. What may be lacking is a good understanding and knowledge of application as a whole, and specific features (such as SLA’s, Business Process Flows etc.). I would invite these people, and in fact anyone who works extensively with CRM, to focus their learning efforts towards the functional side of the application, so that they can ensure they have a good grasp of what CRM is capable of doing with, potentially, just a few mouse clicks. And, finally, to always think twice and consider alternative solutions before deciding on the best option – for everyone involved.