Tip #1130: Refactoring Makes Sense For Configuration Too

If you hang around developers long enough you will hear them use the term “refactoring”. On one project, the developer even had a “Refactor Friday” where this is all they did at the end of the week. So what is refactoring and why should us configuration folks care?

Refactoring is taking existing code and reworking it to simplify it or make it more manageable without affecting what it actually does. In Agile, it is similar to the idea of “technical debt”. As iterative changes accumulate, often a pattern emerges which may not have been apparent at the start. Such a pattern leads to a better approach and rework (tech debt) is needed to align to this approach.

The same can happen to us with configuration. We have lots of tools at our disposal to change the behavior of Dynamics both on the client side and server side. Tools such as Workflows, Business Rules, and Automatic Record Creation allow us to make things happen which, previously, were the domain of the developer. Moreover, often we can produce identical behavior for the user with different tools.

Just as accumulated pieces of code can tread on its own toes, so too can configured behavior. For example, multiple Workflows could trigger off of the same event and overwrite each other’s values or a Workflow and Automatic Record Creation could both send an acknowledgement email on the creation of a Case. This is why it is important that those who configure adopt a developer’s mindset when approaching Dynamics and learn from the developers’ good habits.

While a weekly “Refactor Friday” may be too frequent, set yourself a periodic maintenance task to regularly review your production solution and see if it can be improved through refactoring. Not only will it make your life easier, it will give you an opportunity to reflect on the work you have done and give inspiration for how else you can add value to the users of the system.

Tip #1129: Add features to Dynamics 365 Portal

Even the best of us occasionally make the wrong choice when provisioning Dynamics 365 Portals, especially when Customer Self-Service seems like an obvious all-encompassing choice. Except that it is not. Take, for example, the case of Feridun “Best Twitter Handle for CRM MVP” Kadir:

Problem

I have a D365 instance with the customer self-service portal installed. Is it possible (and if so how please) to add Ideas (which, I believe, is in the community portal solution) to the D365 instance and have Ideas forums appear in the same website that is linked to the customer self-service portal?

Solution

As luck would have it, Microsoft Senior Program Manager, Dileep “Mr Portals” Singh, was able to spare some time to provide step-by-step instructions:

In terms of guidance, I always suggest starting with community template (see, what did I tell you! – t.j.) as it has all customer self-service functionality + extra, and hide the functionality which you don’t need. So if that’s an option in your project, I will suggest doing that. Otherwise:

  1. Install Community Portal solutions in your org which already has customer self-service portal installed. This is done by going to Dynamics 365 Online Admin Center, selecting your organization and clicking on the Solutions tab.
    • Make sure that customer self service and community portal both are at same version as they share solutions within them
  2. After this step is done, you have to make changes to default data which comes with Community Portal. Below is the list of changes.
  3. Web Pages
    • Search for a page called “Ideas” and open it.
      1. Change the Website field to point to “Customer Self Service” site
      2. Change home page to point to “home” page of “Customer Self Service” site
      3. Change Page template field to point to “Page” record associated to “Customer self service” site
      4. Change Publishing state to point to “Published” record associated to “Customer self service” site
  4. Weblinks
    • In the ideas webpage record look for associated weblink records. There should be two “Ideas” weblink associated to “Footer” and “Primary navigation” weblink set
    • Now, open these records one by one and change following fields: –
      1. Weblink set – Make it point to “Primary navigation ” weblink set associated to customer self service website.
      2. Publishing state – Make it point to “Published” state associated to customer self service site
      3. If Parent weblink is filled in, make sure it is pointing to a weblink associated to customer self service site as well.Relink portal data
  5. Content Snippets
    • Search content snippet which Idea term in it.
    • Open the record and change the website field value to Customer self service
  6. Site Markers
    • Search for site markers which has “idea” term in it
    • Open the record and change the website field value to Customer self service

Also make sure while going through these, that you have enabled diagnostic logging, so you can see details of any error which occurs throughout the process. From what I have seen, sometimes you can miss a page and it can lead to some liquid errors in your portal. Also, once all the changes are done, it is a good practice to either restart the portal or clear the server side cache.

Tîpp Jäår $0.02

Note: these steps aren’t published yet in any specific documentation, however, that may change if there are more requests coming in for this. I guess additional votes for the WebSite Copy Tool wouldn’t go unnoticed so go ahead and add your voice!

 

Facebook and Twitter cover photo by Drew Patrick Miller on Unsplash

Tip #1128: What role did I used to have?

Say you move a user to a different business unit, but you forget that when you change a user’s business unit, it removes all of the user’s security roles. How do you find what role the user used to have?

One answer is audit history.

If auditing is enabled for user entity, you will see an “associate” record whenever a role is added, and a “disassociate” record whenever a role is removed. This can also be helpful for identifying who made the change in the scenario where one of the admins does an accidental role update or business unit move.

Tip #1127: Don’t update auto number field

Locked boxes with the engraved numbersWe did mentioned in the past that most of the good inventions are driven by the laziness. Auto numbering the new records is one of those. Instead of manually looking up the next available number, calling other users to see if they have any intention of creating a new record in the next few minutes, and placing dibs on that number, users wanted things to be numbered automatically. So deep was the desire that Dynamics 365 developers went a long way to add this feature. Over the years we’ve had our share of on-premises hacks, both free and commercial solutions that used variety of techniques: slap-slap-slap™, plugins, workflows, external locking services, to name but a few. Finally, the giant woke up and gave us the built-in auto number feature.

The pressure to release was high and some sacrifices were made:

Currently, you can add the attribute programmatically. There is no user interface to add this type of attribute.

Thanks to XrmToolBox Autonum plugin, we can live with that because it’s out of the box, fast and, unlike homegrown brews, has neither deadlocks nor duplicate numbers:

The sequential segment is generated by SQL and hence uniqueness is guaranteed by SQL.

All good? Can we go home now? Well, yes, but then you’re going to miss out on the explanation why Elaiza “Mother of Filipinos” Benitez was having an issue with auto number field not generated for records created via portals.

The most important thing to remember about the auto number field is that it is not new type of a field, it’s simply an additional AutoNumberFormat property that can be defined for strings with the format Text. In fact, as per documentation

You can modify an existing format text attribute to be an auto-number format.

What that means is that all other features that have nothing to do with auto numbering, still apply. The attribute can be optional, and the value can be inserted and updated manually. The only feature that AutoNumberFormat property adds to the attribute is that, when the new record is created and the value for the attribute is not specified, system will generate the next unique value using the defined pattern and the next sequence number. That’s it. For example, if the next sequence number is supposed to generate 00042, it will do so even if you already have a record with that value (say, created manually beforehand).

What about the portals? Portals, by design, will submit any attribute that is present on the form, unless it is read-only. Even if it’s hidden. If attribute value is not provided, portal will set it to null. Autonumbering will respect the explicit value and won’t generate anything, leaving it null (blank). As Jonas “The Shuffler” Rapp has succinctly put it

The numbering feature is designed to respect explicitly given values, even when it is null.

The solution the the portal drama is to either make auto number read-only, or completely remove it from the form.

Here is some of the ideas you may want to consider when using an auto numbered field:

  • Decide what to do with the existing records where the value may exist or is null if attribute is new. If you want to use the generator to update the values, how about repeatedly creating new records, getting the attribute value back, deleting those records, and then using the generated values to update the existing entries.
  • Add an alternate key based on that attribute, if you want to guarantee the uniqueness
  • Set the field to read-only on all the forms
  • Add field-level security to the field and set it as read-only for
    everyone (note: won’t work with alternate keys)
  • Create plugin on pre-validation stage, verify if attribute is present and either stop the create or drop the attribute (which should kick in the generator) (NOT TESTED, just a thought!)

Thanks to Nick “Benchpress” Doelman for some of the ideas for the tip.

Facebook and Twitter cover photo by Tim Evans on Unsplash

Tip #1126: Recycling Entities Does Not Always Make Sense

To all our American comrades – Happy Independence Day!

My current project is for a university. People enrol, they study, they graduate and become alumni. On a couple of occasions I have met with internal staff who have ideas on Dynamics design. Those that come from a pure database background seek to devolve every interaction into an intersection of three tables: Party 1, Party 2, and an interaction type. For example, a Student and a Degree with an action of Enrollment.

Those that come from the business side and have some knowledge of the Dynamics structure seek to apply their business model to existing Dynamics structures. For example, isn’t a student enrollment similar to a sales Opportunity? We have a customer, we have products, which are like Degrees, and enrollment is like closing the Opportunity, right?

While well meaning, both positions miss the mark. In theory, a three table interaction could be generated within Dynamics and this may well be “best practice” in database design. However, it throws away all the richness Microsoft has built into Dynamics. For example Automated Lead to Opportunity conversion, Outlook and Office integration, and in-built dashboards and templates are rendered useless and have to be rebuilt from scratch.

Similarly, in trying to over-recycle existing entities, we tangle ourselves up in this richness and it becomes baggage to work around. Degrees do not work like Dynamics Products and the things we need for one do not apply to the other (what is the Product equivalent of a degree course, for example?) While in other systems it is hard work to generate custom entities, and this is often the motivation for recycling, it is quite easy in Dynamics and should not be feared.

Finding the balance of where to build new structures and where to use existing ones is often more art than science and relies on the experience of having tried it in the past. This is one of the reasons why when asked what the best thing you can do to ensure the success of a Dynamics implementation is, I reply get a Microsoft partner (or MVP) involved. Let their past successes (and occasional failures) guide you.

Tip #1125: Busy times and say .NYET to .NET

You probably have noticed a somewhat reduced stream of daily tips. “More like tip of the week now” you say and you’d be right. We’ve been extremely busy in the last couple of months:

  • countless pints consumed in between awesome sessions at CRMUG EMEA in Dublin
  • despite my inept organizational abilities, the inaugural BAD Masterclass was a success, that we hope to replicate in US/Canada and Australia
  • financial year 2018 done and dusted
    Bank account overflow warning
  • all in-house tipsters had their MVP Award renewed on the 1st of July

Last but not least, as the title of the post suggests, we’ve been busy cooking in the non-.NET space, namely PHP. We’ve had our PHP CRM Toolkit and Dynamics 365 WordPress Plugin out in the wild for a while but it is time to move on and embrace Dynamics 365 Customer Engagement Web API.

Without further ado, let us present the first public release of Dynamics 365 Web API toolkit. It’s work in progress, naturally, and your feedback and participation are welcome.

We are back to our daily tipping routine. While we were taking a small break from tipping, the Dynamics 365 world has been humming along nicely and we now have a backlog of things to share with you. Stay tuned!

Facebook and Twitter cover photo by Karlijn Prot on Unsplash

Tip #1124: Flow Approvals May Be Exactly What You Need

Back in Tip #880, we mentioned Approvals in Flow. Specifically, we said:

…use the flow approval framework and even have people who don’t have Dynamics licenses approve stuff.

Given the implications of this for Dynamics, it is worth exploring further.

If you have not explored Approvals in Flow, it is worth a review. A unique feature of Flow, they allow a group of people to approve an action. The decision to approve can be configured to be by any one individual or by the group as a whole. The only catch is the people assigned to approve must have their email in the same domain as the account the Flow is running under, but that is about it.

When the Approval action is triggered, an email is sent to the approver(s) requesting their input. They can approve or reject and there is a text box to apply additional feedback. Depending on your email client, this can be done directly in the email. Otherwise, clicking Approve/Reject opens a web page for the approver to log into their AD account and the approval is done from the Flow site. Finally, if the approver has the Flow app installed on their phone, the approval can also be done from there.

So why is this so interesting? Let us consider this in the context of Dynamics. Let us say we need input on a Case or Opportunity by someone in our organisation who is not a Dynamics user (a group of engineers giving expert advice on a Case, for example). What are our options? In the Dynamics stack, the two obvious ones would be PowerApps or a Portal form. However, for both of these it is clear there is a license implication. The approver is interacting with Dynamics data, albeit in a non-interactive way, and they will need a team license or something similar. For an organisation with thousands of non-Dynamics staff, this can be quite expensive.

So does Flow Approvals fall under the same category? Well, it is not as cut and dried. It is quite straightforward to have a Flow Approval trigger from an action in Dynamics, such as the creation of a record (or the ticking of a box on a form). It is also quite straightforward to take the response of the approver and have the Approval step pass that through to Dynamics. However, all the Flow does is send and receive an email to and from the approver. Arguably, the approver is not interacting with Dynamics at all; the Flow is, under the account of the Flow administrator. Even if we consider this a ‘double hop’ interaction, all the approver is doing is responding to an email. Traditionally, emails coming into Dynamics have not had a license implication, no matter how they are parsed once inside.

If we look at the Flow licensing page, it says for all but the free Flow plan, Flow usage is for all company users and connectivity to Dynamics 365 is included in all plans. I know how I interpret this but you will want to check with your local Microsoft contact for an official ruling before relying on it in a production system.

Tip #1123: Audit data reads in Dynamics 365

Whether you care about GDPR or not, the changes made to the Dynamics 365 platform to comply with GDPR have a positive impact on all Dynamics 365 users. One of those changes involves auditing.

Traditionally Dynamics 365 auditing has been on the data update level–who changed a record. With the GDPR updates, a wide variety of additional user processes can now be audited, including many administrator functions and data reads.

See the official documentationfor the full list of events, but here are some of my favorite additions:

  • Who published customizations
  • Who was added to a team
  • Who added a solution
  • Who published customizations
  • Who exported to Excel
  • Who viewed a report
  • Who exported a report

This is an exciting addition. Make sure you pay attention to the prerequisites.

  • An Office 365 Enterprise E3 or E5 subscription is required to do Activity Logging.
  • For version 8.x, version 8.2.2.1310 or later is required.
  • Available for production and not Sandbox instances.

Tip #1122: Multiple tokens in cache

If you are working with multiple user or app identities (e.g. for testing), and the code uses ADAL, and especially if the application is killed or crashes, you may occasionally get an error:

multiple_matching_tokens_detected: The cache contains multiple tokens satisfying the requirements. Call AcquireToken again providing more requirements (e.g. UserId)

Note that it does not have to be your code, it could be another application that uses Xrm.Tooling (that does use ADAL), for example. I encountered this error while working with Package Deployer where it fails to load the solution and if you click View Log Files (tucked away in the left bottom corner), you’ll find something like this at the bottom of the file:

PackageDeployment Information 8 5/06/2018 1:34:21 AM Status: Importing solutions
PackageDeployment Error 2 5/06/2018 1:34:21 AM Message: Failed to execute DoImportSolutionItem Method
Source : Microsoft.IdentityModel.Clients.ActiveDirectory

followed by the multiple_matching_tokens_detected error described above.

The root cause is somewhat clear: ADAL gets confused after searching token cache and finding multiple tokens for the same authority/resource/clientid combination but for different users. The solution is to reset the token cache for the application that uses it. It is per application and located in the appdata folder for that application. For Package Deployer, for example, token cache is the file Default_PackageDeployer.tokens.dat and located in the C:\Users\<username>\AppData\Roaming\Microsoft\PackageDeployer folder. Delete that file and you are as good as new.

While you’re at it, take a look at Default_PackageDeployer.exe.config file located in the same folder. This is where Package Deployer saves the last connection information, feel free to play with it (at your own risk, that is). The most ubiquitous Plugin Registration tool has its stuff in, you guessed it, C:\Users\<username>\AppData\Roaming\Microsoft\PluginRegistration folder, in case you need it.

Facebook and Twitter cover photo by Tyson Dudley on Unsplash

Tip #1121: What happens if an email is sent to multiple queues?

This tip comes from my colleague Bruce Sithole who did the hard yards to find out the answer to this question. As it turns out, the behavior is a little unpredictable. Firstly, multiple queues can process the email and create a Case. The order of processing appears to be first polled, first served. Also, there is a timing element in that after a period of time (presumably after some kind of flag set on the email, additional queues no longer process the email. So, for example, if an email is sent to the email of four queues, three Cases may be created.

So where does the email get attached to? Well, it gets passed between the Cases, as they are created. In this game of pass the parcel, the last Case created is the one that ends up with the prize when the music stops.

So how do we manage this in the real world when we only want one Case created for one email?

Alas, in this situation we will likely have to rely on code for a bulletproof solution. The best approach we came up with was to manipulate the email record, pre-create via a plugin, so that we could identify the preferred queue, mark as such on the email and then use this as a check on the Case creation. It is a tricky one though so if you know of another way to handle this (other than, you know, having one queue and then distributing once it is in Dynamics) feel free to comment.