Tag Archives: Microsoft

Microsoft Dynamics 365: Varying Form Behavior On Form-type and Save-mode

Microsoft Dynamics 365 offers the ability to vary the behavior of forms based on the form type and how the form is saved, using JavaScript. In this blog post, we cover how we can make use of this flexibility offered by the platform to deliver unique solutions for end users.

Summary of the key syntax

Here is a high-level summary of the main Microsoft Dynamics 365 JavaScript syntax covered in this blog post.

  • Getting the type of form:
    formContext.ui.getFormType();
  • Hide a tab on a form (where “TabName” represents the name of the tab you would like to hide):
    formContext.ui.tabs.get("TabName").setVisible(false);
  • Get the object with methods to manage the Save event:
    executionContext.getEventArgs();
  • Get the form Save Mode:
    executionContext.getEventArgs().getSaveMode();
  • Inhibit the default save behavior on a form
    executionContext.getEventArgs().preventDefault();
  • Check if the default save behavior was inhibited
    executionContext.getEventArgs().isDefaultPrevented();
  • Get the form context
    executionContext.getFormContext();

Form Type

To get the Form Type, you use the following JavaScript code:

formContext.ui.getFormType();

Here are the different Dynamics 365 form types and their respective JavaScript return values:

Form type Return Value
Undefined0
Create1
Update2
Read Only3
Disabled4
Bulk Edit6

Application Example: Varying form behavior on Form Type

In this application example, we will hide the Products and Services tab on the Create type form (with JavaScript Return Value = 1). However, it will be still be visible on all other applicable form types. This prevents users from adding information to the Products and Services tab before a Contact record has been created and saved. Therefore, the user must first create the Contact record (using the Create form type) and after the record has been created, the users will be presented with the Update form type (with JavaScript Return Value = 2) and will be able to access the Products and Services tab as well as its contents.

The Contact entity’s create form type will look similar to this (i.e. the Products and Services tab is hidden):
Contact - Create form type

In contrast, the Update form type still shows the Products and Services tab.
Contact - Update form type

Here is the code to executes the requirement above.

//Hide Products and Services tab on Create form 
function HideProductsServicesTab(executionContext) {   
  //Get form context   
  var formContext = executionContext.getFormContext();   
  //Get form type   
  var formType = formContext.ui.getFormType();   
  //If formtype is Create, hide Products and Services tab on form     
  if (formType == 1) {
    formContext.ui.tabs.get("productsandservices").setVisible(false);   
  }   
  //To see the form type return value in your browser console
  console.log("Form type = " + formType); 
}

Save Mode

To get the form’s Save Mode, you use the following JavaScript code:

executionContext.getEventArgs().getSaveMode();

Here are Dynamics 365’s different Save Modes and their respective JavaScript return values as well as the applicable entities.

Entity Save Mode Return Value
AllSave1
AllSave and Close2
AllDeactivate5
AllReactivate6
EmailSend7
LeadDisqualify15
LeadQualify16
User or Team owned entitiesAssign47
ActivitiesSave as Completed58
AllSave and New59
AllAuto Save70

Application Example: Varying form behavior on Save Mode

Here is an example of how you can vary the form’s behavior on the Save Mode.

//Inhibit auto save functionality on a form
function InhibitAutoSave(executionContext) {
  var eventArgs = executionContext.getEventArgs();
  //To see the Save Mode return value in your browser console
  console.log("Save Mode = " + eventArgs.getSaveMode());
  //If save mode is 'Save and Close' or 'Auto Save', inhibit default behavior i.e. save 
  if (eventArgs.getSaveMode() == 2 || eventArgs.getSaveMode() == 70) {
    eventArgs.preventDefault(); 
  } 
  //To see if the auto save behavior was prevented in your browser console
  console.log("Default behaviour prevented: " + eventArgs.isDefaultPrevented());
 }

If you have some unsaved changes on a form, the code above inhibits the regular form auto save behavior as well as inhibits the regular Save and Close auto save behavior, that you ordinarily get when you navigate away from from a form with unsaved changes. Instead of auto-saving (i.e. the default behavior), if you try to navigate away from a form with an unsaved changes, the JavaScript code above will block the auto save behavior and offer you the pop up notification below. If you choose “OK”, you will loose all your unsaved changes, and if you choose “Cancel”, you will remain the same form. With the default auto save behavior inhibited, users have to manually save the form, by clicking on the Save button or using the keyboard shortcut: “Control + S”.
Auto Save Inhibited: Do you want to loose your changes?

What if you want to inhibit the auto-save behavior throughout your Dynamics 365 organization (i.e. disable auto-save on all forms), instead of a specific form? It would be inefficient to implement the JavaScript code above on all forms across all your Dynamics 365 organization entities. An efficient way execute such a requirement (i.e. on all forms) is to:

  1. Go to Settings > Administration.
  2. Click on System Settings.
  3. Click on the General tab
  4. Set the Enable auto save on all forms option, to No.
  5. Click OK, in the footer of the window.

Disabling Auto Save in a Dynamics 365 Organization

Microsoft Dynamics 365: How to Remove Unwanted Special Characters from Text Fields

Microsoft Dynamics 365 has a flexible and extendable architecture, and can be integrated with other platforms. In integrations, it is common for data entered in Dynamics 365 to be shared with other platforms. Although Dynamics 365 text fields are flexible to save special characters, other platforms, that integrate with Dynamics 365, may not be as flexible. For example, when you integrate Dynamics 365 with SharePoint or One Drive, you may want to use the record’s name in Dynamics 365 to create the record’s document set or folder in SharePoint or One Drive . In such a case, Dynamics 365 fields being used by SharePoint or One Drive have to adhere to those platforms’ more restrictive special characters restrictions. The the invalid characters for OneDrive, OneDrive for Business on Office 365, and SharePoint Online are ” * : < > ? / \ | and for OneDrive for Business on SharePoint Server 2013 they are ~ . ” # % & * : < > ? / \ { | }.

The plugin in this post addresses this integration challenge by preventing users from saving restricted special characters in the text field(s) enabled text validation. When creating or updating a record in Dynamics 365, the plugin will check the text field(s), enabled for text validation, and strip out the characters that are not part of the permitted list characters.

To demonstrate this plugin’s functionality, we enabled text validation on the Account Name field for the Account entity. The validation rule applied by the plugin is: the Account Name field is only permitted to take in alphanumeric characters, space and 2 special characters i.e. underscore and hyphen. If a user enters any characters in the field, other than the permitted list of characters, they will be stripped out when they save the record. In the image below, a user entered both valid and invalid characters. Before Save:
Before Saving, user has entered invalid special characters

When saving the record, the plugin stripped out the invalid characters from the text field, leaving only the permitted characters (i.e. alphanumeric characters, space and 2 special characters i.e. underscore and hyphen). After Save:
After Saving, invalid special characters are removed

The Plugin

using System;
using System.Text.RegularExpressions;
using Microsoft.Xrm.Sdk;


namespace ItsFascinating.Plugins.D365
{
    /// 
    /// This plugin removes non-approved special characters from the Account Name field of the Account entity
    /// 
    public class AccountNameCharactersRemover : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            string pluginMessageCreate = "create";
            string pluginMessageUpdate = "update";
            Entity primaryEntity = new Entity();

            if (serviceProvider == null)
            {
                throw new ArgumentNullException("localContext");
            }

            #region Plugin Setup Variables
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            #endregion
            #region Validation Prior Execution
            //Exist if plugin if it's not called at stage 20 of the excution pipeline
            if (context.Stage != 20)
            {
                tracingService.Trace("Invalid Stage: Stage = {0}", context.Stage);
                return;
            }
           
            //Only execute plugin if plugin message is Create or Update 
            if (!(context.MessageName.ToLower().Equals(pluginMessageCreate) || context.MessageName.ToLower().Equals(pluginMessageUpdate)))
            {
                tracingService.Trace("Invalid Message: MessageName = {0}", context.MessageName);
                return;
            }
            #endregion

            #region Plugin Logic
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                try
                {
                    primaryEntity = context.InputParameters["Target"] as Entity;
                    
                    // Display Name: "Account Name" | Database Name: "name"
                    string accountNameFieldLogicalName = "name";
                    Object accountNameObj;
                    string accountName, updatedAccountName;
                    //Regex pattern for alphanumeric characters, space and 2 special characters i.e. underscore and hyphen                 
                    string permittedCharacters = "[^0-9a-zA-Z_ -]+";
                   
                    //Check if the specified attribute is contained in the internal dictionary before you you try to Get its value
                    if (primaryEntity.Attributes.TryGetValue(accountNameFieldLogicalName, out accountNameObj))
                    {
                        //Get value of that has been entered in the text field
                        accountName = Convert.ToString(accountNameObj);
                        //Remove remove unpermitted characters
                        updatedAccountName = Regex.Replace(accountName, permittedCharacters, "");
                        //Update the value of the text field, after removing the restricted characters
                        primaryEntity.Attributes[accountNameFieldLogicalName] = updatedAccountName;
                    }
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException(string.Format("Error occured in the PreUpdateAccount plugin: {0}", ex.Message));
                }
            }
            #endregion
        }
    }
}

The Microsoft Dynamics 365 Custom Control Framework

In version 9 of Dynamics 365 / CRM, Microsoft introduced the Custom Control Framework, which gives Dynamics 365 customizers and developers more options on how to display fields and data-sets, such as views. The Custom Control Framework offers a wide range of aesthetically appealing displays, enabling you to transform regular fields and data-sets into more appealing visualizations that are likely to increase user engagement and enhance user experience.

Examples

The default display for a numeric input field, i.e. Whole Number, Decimal, Currency, Floating Point Number, is:

Numeric Field - Default Display

Using the Custom Control Framework, you can transform this regular numeric input field into other displays such as Number Input, Arc Knob, Radial Knob, Linear Gauge, Linear Slide, Star Rating, among others.

Numeric Field - Other Display Options

Depending on the type of input field, different Custom Control Framework displays are available. For an Option Set field, the regular display is:

OptionSet - Default Display

Using the Custom Control Framework’s Option Set, it can also be displayed as tiles:

OptionSet - Tiles Display

How to Implement the Custom Control Framework

Step 1: Go to the edit mode of the entity’s form that you wish to apply the Custom Control Framework to. In the example below, I will be editing the Account entity’s Account form.

Account form in edit mode

Step 2: Click on the field you would like to apply the Custom Control Framework to. In the ribbon, click on ‘Change Properties’.

Step 3: In the Field Properties window that pops up, select the ‘Controls’ tab.

Field's Controls tab

Step 4: Click on “Add Control…”. Then select the control you would like to apply (1 – image below). Having selected the control you would like to apply, click ‘Add’ (2 – image below).

Note: In the example below, I am applying the Custom Control Framework to a numeric field.

Add a Custom Control

Step 5: Set the properties of the control. Select the devices you want your control to be displayed on i.e. Web Browser, Phone, Tablet (1 – image below). Enter the control’s properties i.e. Min, Max and Step values (2 – image below). Click ‘OK’ (3 – image below).

Set the control's properties

In (2 – image above), you can bind the Min, Max and Step values to a static value (A – image below) or to another field (B – image below).

Binding min, max and step values to a static value or field.

Step 6: Save and publish the entity’s form. You can now go and view the published version of the form to see your custom control in action.

Depending on the type of input field selected, different Custom Control Framework displays are available in Step 4 above. Also, the properties available in Step 5 are dependent on the type of input field selected . That is, the Custom Control Framework displays available for a numeric field are different from those available for an option set field.

Conclusion

As shown above, the Custom Control Framework offers organizations more options for displaying fields and has a nice aesthetic touch. However, like all tools, Dynamics 365 customizers and developers, have to assess their client’s needs and determine whether to use the default displays or the Custom Control Framework displays.

Microsoft Dynamics 365: How to Set Up a Free Online Trial Version

For organizations seeking a comprehensive, robust and extendable customer relationship management platform, it is worth considering the Microsoft Dynamics 365 platform. In this post, we will cover a quick case for considering Microsoft Dynamics 365 for your customer relationship management and provide a guide on how set up a free Dynamics 365 Online 30 day Trial Version.

A Quick Case for Microsoft Dynamics 365

Why should you choose Microsoft Dynamics 365 over other customer relationship management platforms? Here are 6 reasons to choose Microsoft Dynamics 365 over its competitors:

  • Familiar, intuitive and easy to adopt user interface: If an organization is familiar with the Microsoft Office suite, it is easy to adopt the Microsoft Dynamics 365 user interface, as they are designed by the same organization. You can spend less on change management.
  • Integration with the Microsoft ecosystem: You can easily integrate Microsoft Dynamics 365 with the rest of the Microsoft ecosystem like Outlook, Office 365 (Word, Excel, PowerPoint, Outlook, etc), Windows Server, Exchange Server, Skype for Business, SharePoint, Power BI, and PowerApps.
  • Powerful analytics, social sales and embedded intelligence features like LinkedIn Sales Navigator Application Platform and Relationship Assistant, to enhance productivity, efficiency and effectiveness.
  • Flexible and extendable architecture, deployment options, and pricing, making it easy for an organization to customize Dynamics 365 to its specific requirements and only pay for its unique needs.
  • Detailed, flexible and seamless security model: Dynamics allows you to control who can access general sections and specific areas like fields. Users only see areas they have been granted access to.
  • Microsoft’s commitment to the product quality and innovation as well as partner support: Microsoft is committed to quality and regularly releases updates, continuously innovating and improving the product. Also, Microsoft has a global network of partners to support clients across the world.

Setting up a Microsoft Dynamics 365 Free Online Trial Version

Are you convinced about Microsoft Dynamics 365? If you are, and ready to take it to the next level, here are the steps you need to set up a Microsoft Dynamics 365 online trial version:

Step 1: Go to the Microsoft Dynamics 365 product home page.
Dynamics 365 product home page

Step 2: Click on “Schedule a demo”.
Click on "Schedule a demo"

Step 3: Click on “Sign up for a free trial”.
Sign up for a free trial

Step 4: Click on “Sign up here”.
Click on "Sign up here"

Step 5: On the pop-up, if you are not a Microsoft employee or partner organization, click on “No, continue signing up”.
If you are not a Microsoft employee or partner organization, click on "No, continue signing up"

Step 6: Enter the required information and click “Next”.
Enter the required information and click on "Next"

Step 7: Enter the required information about the Microsoft Dynamics 365 trial organization you are about to create and click on “Create my account”. Also, if you would like to hear from Microsoft or its partner in your geographical location to provide support on your Dynamics 365 journey, select the options provided below.
Click "Create my account"

Step 8: Enter your phone number for Microsoft to verify that you are not a robot. You will receive an automated text or phone call, depending on the option you select.
Enter your phone number to verify that you are not a robot

Step 9: Hooray!!! You have created your Office 365 and Dynamics 365 organizations, you will get the page below. Take note of the “Sign-in page’ and “Your user ID”, you will need this information to sign into your new organization.
You have created a D365 organization

Step 10: Go to the Microsoft Office 365 home page. If you are requested to sign in, click on “Sign in” and login using the user ID from step 9 and the password you created earlier, in step 7.
Go to Microsoft Office 365 home page and sign into the organization you created in Step 9.

Step 11: After logging in, click on the “Admin” app, to access your Office 365 organization’s administration options and configurations.
Office 365 home - select Admin app

Step 12: Adding other users to your new Office organization and Dynamics 365 organization: In the Admin app, navigate to Users >>> Active Users. You will get a page similar to the one below. Click on ‘Add a user’ to start the process of adding a new user to the Office 365 organization.
Add other users

Step 13: Enter the user’s basic information and click Next:
User's basic info

Step 14: You can add a user to your Office 365 organization without giving them access to the Dynamics 365 organization. However, if you if you want the user to be both a member of the Office 365 organization and Dynamics 365 organization, you have to grant the user a Dynamics 365 license (see the image below). You can also assign the user other product licenses from this section. Click Next.

The creator of the organization has a Global Administrator role, in Office 365, as well as System Administrator and System Customizer security roles, in Dynamics 365, giving them the rights to add users to both Office 365 and Dynamics 365.
Assign licenses

Step 15: You can also assign administration roles to the user if you wish. These settings are optional. Click Next.
Optional settings

Step 16: Review the user details. If you have happy with the setup details, click on ‘Finish adding’ to add the user to the organization.
Finish adding user

Step 17: After successfully adding the user, you will get a page similar to image below. You can add more users from this window. After you finish add users, click ‘Close’.
Successfully added user

Step 18: Back in the Admin page, in the left navigation, navigate to ‘All admin centers ‘. If you cannot see ‘All admin centers ‘ in your left navigation panel, click on ‘Show all’. In the main window, click on ‘Dynamics 365’ to access the Dynamics 365 administration center, in order to complete the set up of your Dynamics 365 organization.
All Admin Centers

Step 19: To complete your Dynamics 365 setup, select the apps you are interested in. If you are not interested in the provided apps, you can select “None of these. Don’t customize my organization” for a vanilla Dynamics of 365 organization. Click on ‘Complete Setup’.
Select the Dynamics 365 apps you are interested in.

Step 20: Depending on the app(s) you selected in the previous step, you will get a launch pad similar to this:
D365 Published Apps

Step 21: Select the Dynamics 365 app you would like to launch by clicking on it and you will get the app’s home page. Here is an example of the Dynamics 365 Customer Service app home.
D365 -Customer Service

Your brand new Dynamics 365 instance has been set up and is ready for your adventures. Feel to explore and play around with the environment. You just have entered the fascinating world of Dynamics 365. Welcome!!!

Optimize Entity Attributes Access in Dynamics 365

I was recently working at a client site and came across the error/exception below. A plugin I had developed a few weeks earlier stopped working in the integration environment after an update to a different class/plugin. The error did not make sense and sent me on a wild goose chase for a few hours. How can code function in one environment and not in another environment, when one environment is a replicate of the other and all the parameters as well as infrastructure is the same? As a software developer, the favorite part of my job is coming across such conundrums.

The Error

“The given key was not present in the dictionary” exception

This was as much information as I could get from the system. This exception indicates that I was trying to access an attribute that was not present in the internal .NET dictionary. I looked very closely at both environments and they had all the entity attributes I was accessing in the plugin.  

In investigating this error, I came across a more efficient way to access entity attributes in Microsoft Dynamics 365. Often, before Dynamics 365 software developers perform logic on a retrieved value, they have to check if the retrieved value exists. Executing such logic usually follows the following path or something similar (we use the Contact entity in this example but this can be applied to any out of the box entity or custom entity):

Accessing attributes using Attributes.Contains() method

//Declare the contact entity and retrieve it from the execution context
Entity contact = pluginExecutionContext.InputParameters["Target"] as Entity;
//Check if attribute exists in collection, using Attributes.Contains
if (contact.Attributes.Contains("company"))
{
    //Get attribute of interest, as a string
    string contactCompany = contact.GetAttributeValue("company");
    //Perform operations on your attribute of interest
    /*
    */
}

Accessing attributes using Attributes.TryGetValue() method

//Declare the contact entity and retrieve it from the execution context
 Entity contact = pluginExecutionContext.InputParameters["Target"] as Entity;
 //Object that will store the attribute object if the retrieval is successful
 Object contactComp;
 //Check if attribute exists in collection, using Attributes.TryGetValue
 if (contact.Attributes.TryGetValue("company", out contactComp))
 {
    //Get attribute of interest, as a string
    string contactCompany = (String)contactComp; 
     //Perform operations on your attribute of interest
     /*
     */
 } 

Despite the Attributes.Contains() method and the Attributes.TryGetValue() being used to achieve the same objective, the latter is more efficient. When you use the Attributes.Contains() method, your code is performing two look up operations in the background. First, it checks if the specified attribute is contained in the internal dictionary. If the dictionary contains the specified attribute, another look up will be performed to get the corresponding value for the attribute. The Attributes.TryGetValue() method performs both operations in one swoop by returning a Boolean value, true (value exists) or false (value does not exist), and an output object, which contains the attribute value.

If you are only accessing the attribute dictionary as shown above, a few times, you may not see significant savings in execution time, by using Attributes.TryGetValue(). However, as the application grows and you are performing these operations regularly or in a loop, the code optimizations benefits of using Attributes.TryGetValue() become self-evident.

To learn more about Attributes.TryGetValue() method, look at the Microsoft documentation: TryGetValue().

Conclusion

The Attributes.TryGetValue() method resolved the exception I was getting within my plugin and optimized my code. This is more than what I had bargained for when I began my investigation, which is a terrific and extremely rewarding outcome. Therefore, I would recommend the Attributes.TryGetValue() method over the Attributes.Contains() method.