Tip #1143: Managing Dynamics Goes Beyond Technology

It is easy to focus on training and certifications and think this will be enough to implement or maintain a successful Dynamics system but, especially with process management systems like Dynamics, being tech savvy is not enough.

Certainly knowing the system, its limitations and capabilities is important but understanding the impact of change is vital for success. The traditional paradigm is People, Process, and Technology with a change in one having an impact on the other.

To successfully administer or implement Dynamics, here are some of the skills and talents you will need access to:

People

  • Change communication: The ability to articulate what is coming, why it is beneficial, and to get buy-in
  • Capable trainers/technical writers: The ability to empower the users to embrace the change
  • Effective feedback mechanisms: Telling is one thing but listening is vital

Process

  • Process discovery: Find out how things are done and how they will be impacted through change
  • Process modelling: Documenting process, an often overlooked task, provides the opportunity to reflect and review where the biggest improvements can be made
  • Process performance management: Establishing measures for what defines a successful process provides proof of the benefits Dynamics is bringing

Technology

  • Functional knowledge: No point reinventing the wheel when it comes standard. Knowing what Dynamics provides means knowing how to use it to the best advantage
  • Technical knowledge: Where Dynamics ends, development begins. Knowing how to extend Dynamics takes a good system and makes it great
  • Roadmap knowledge: Knowing the future of Dynamics means developing the system to work with Microsoft and their vision for the product, not against it. Significant effort can be saved with a little hindsight.

Tip #1142: Tracing in Azure Functions MkII

When describing tracing  in Azure Functions previously, I dropped almost in passing that to capture .NET traces in Azure Functions is easy – just create your own TraceListener. I also added that

the code takes a shortcut with log.Info and requires a bit of tuning like mapping logging levels from Connector to TraceWriter but those are the details we can live without

On one of the existing projects, that extensively uses Trace, I had an opportunity to eat my own words. Turns out, we cannot live without those pesky details because logging level will be totally useless in that implementation.

Getting levels under control turned out to be a small challenge because, technically speaking, listener is just that and shouldn’t concern itself with the logging level – you do what you’re told, basically. After some table bending up-and-down head movements, I managed to come up with TraceWriterListener class that takes Azure Functions log interface as a parameter and correctly intercepts all levels of tracing, emitting the appropriate statements. Here is the class in all its glory:

using Microsoft.Extensions.Logging;
using System.Diagnostics;

namespace YourNamespace
{
  // Log writter for working with Azure Functions 
  public class TraceWriterListener : TraceListener
  {
    private ILogger _log;

    public TraceWriterListener(string name, 
          ILogger logger) : base(name)
    {
      _log = logger;
    }

    public TraceWriterListener(ILogger logger) : base()
    {
      _log = logger;
    }

    // this is the one we have to overwrite to get 
    // the logging level right
    public override void TraceEvent(
          TraceEventCache eventCache, 
          string source, TraceEventType eventType, 
          int id, string message)
    {
      switch(eventType)
      {
        case TraceEventType.Verbose: 
          _log?.LogDebug(message); 
          break;
        case TraceEventType.Information: 
          _log?.LogInformation(message);
          break;
        case TraceEventType.Warning: 
          _log?.LogWarning(message); 
          break;
        case TraceEventType.Error: 
          _log?.LogError(message); 
          break;
        case TraceEventType.Critical: 
          _log?.LogCritical(message); 
          break;
        default:break;
      }
    }

    public override void Write(string message)
    {
      _log?.LogTrace(message);
    }

    public override void WriteLine(string message)
    {
      _log?.LogTrace(message);
    }
  }
}

If you add this class to your function project (or drop as csx into your function environment if you are not using projects), then the function code can use something like:

public static void Run(
  [TimerTrigger("0 0 0 1 1 *")]TimerInfo myTimer, 
  ILogger log)
{
   var logger = new TraceWriterListener(log);
   Trace.Listeners.Add(logger);
   Trace.TraceInformation($"Information");
   Trace.TraceWarning($"Warning");
   Trace.TraceError($"Error");
   Trace.WriteLine($"Level comes from ILogger");
}

which makes migration of the existing code fairly easy.

Bonus

You probably noticed the use of ILogger interface where previously TraceWriter was sitting. As of recently quite some time ago, functions now have support for logging through the Microsoft.Extensions.Logging.ILogger interface. As per documentation: at a high level, this is not much different than logging via the TraceWriter: logs continue to go to the file system and will also go to Application Insights (currently in Preview) if the APPINSIGHTS_INSTRUMENTATIONKEY app setting is set. The main advantage of using ILogger is that you get support for structured logging via Application Insights, which allows for richer Analytics support. To use ILogger as your logging interface, simply add a parameter to your function signature and use any of the logger extensions.

Tip #1140: Get ready for October 2018 release

No, Microsoft didn’t invent the time machine (though you can buy one in store). As part of modernizing the way Dynamics 365 gets updated, the team has just released October 2018 release notes.

Why did the notes get released 3 (and for some features 5) months ahead of schedule? So that customers and partners can start planning for the new and exciting capabilities coming to Dynamics 365. This is also a great opportunity to provide early feedback (by emailing releasenotes@microsoft.com) that will be reviewed and incorporated, if applicable and makes sense.

Overall, the document is a mixed bag. It’s understandable because the contributions were coming from the independent teams. Still, it’s hard to place features like “Improved grid with copy and paste” in Business Central on the same level as Channel Integration Framework.

What caught my attention (YMMV, as I have a developer/platform/ISV bias):

  • Sales: Integration with Microsoft Teams and AI capabilities
  • Service: Service scheduling using URS (Unified Resource Scheduling), Omni-channel Engagement Hub, Channel Integration Framework, and Bring Your Own Bot capabilities
  • Portals: SharePoint integration, embedded Power BI charts, and (finally!) configuration migration schema for portals
  • URS: General enhancements, in-form scheduling, and self-service scheduling APIs
  • PowerApps: embedded canvas apps on entity forms, custom size and responsive layout for canvas apps, ALM and admin enhancements, native support for CDS data types
  • Flow: design Flows in Vision o__O, Flow inception (Flow management connector)
  • Data Integration: new and improved development and consumption for connectors

Commitment to online couldn’t be made clearer with the word “premises” mentioned only in relation to Russian localization of Finance and Operations, Dynamics 365 for Retail, Business Central, and On-premises Data gateway.

Download 239 pages (including 14 pages of TOC) of goodness, get a drink of your choice, and spend a few minutes (or hours) reading it – it will be most certainly worth your time.

(Facebook and Twitter cover photo by Bud Helisson on Unsplash)

Tip #1139: Giving Good Demonstration

Agile projects have ‘ceremonies’ which is code for compulsory meetings with various purposes. One of these ceremonies is the ‘showcase’ where the developers get to show what they have built during the sprint. When you have a new sprint every three weeks, you get used to presenting bits of functionality. Whether it is a fifteen minute showcase presentation or a two hour pre-sales demonstration, there are some things I always do without fail. Here are my tips for Dynamics demos.

Write a Script

If you are behind a keyboard walking through functionality, no one cares if you have a sheet of paper next to the keyboard guiding you. Generally my script has two sections: The Setup and the Running Sheet.

Document the Setup

The setup lists which browsers you are using, what URL you are going to in each tab, the default screen you are starting on and the login (and password hint if required) you are using. While the security purists will frown at the idea of a password hint, the last thing you want to be doing is guessing a password in front of a crowd.

Document the Running Sheet

This is what you will be showing. I generally set it up as a table of two columns: ‘Action’ and ‘Points To Make’. It is very easy to forget the “so what?” factor when showing a software feature so the ‘Points to Make’ column is a great way to have a checklist of points you wish to cover for those audience “aha! moments”.

Run Through the Script

Do this at least once before the real thing. I usually need at least a couple of run throughs,with adjustments, before the demonstration runs smoothly. It might take you 30 minutes to run through and perfect that 15 minute presentation but it is worth it.

Put in Data

Running through the script will quickly show where you need data in the system to support your presentation. Do not compromise an otherwise great show with dodgy data. Get rid of those records named ‘Test’ and use something meaningful to the audience. Again, it may take you three times as long to set up the data as it takes to present but it is worth it.

Do Not Forget to Reset

If you run through your script you will likely be altering the system as you go. Always remember to remove the data from the fields you populated and delete those records you created. Otherwise the audience may see the punchline before you have given them the setup.

Know Your Audience

Know your audience and play to them. I once presented a security background check system in Dynamics to a government department. Thinking it might get a few smiles, my sample contact was the current Prime Minister. It did not go down well. If unsure, use characters from pop culture such as The Simpsons, Harry Potter or Game of Thrones. Seeing a background check done on Jon Snow or Severus Snape will get a wry smile from the fans while the rest will be none the wiser.

Set up Early

Always set up early. This gives you a chance to check internet speeds, connectivity to projectors, required resolution so the audience can see clearly and all the other things you need to do for a smooth presentation. Arriving just on time guarantees the audience will see you fiddling with cables and browsers. Everything should be in place before the first person arrives.

There are many other things you can do to nail your presentation but these are my minimums that I do every time. If you have other must-dos, feel free to leave them in the comments.

Tip #1138: Obtenga your Dynamics 365 trial dans la правильном Sprache

Dynamics 365 supports 43 base languages, and sometimes you need the right one for the trial. In theory, it’s as easy as 1-2-3:

Un

Clément “French but not Tanguy” Olivier was having no luck provisioning a trial instance in his langue maternelle:

For a client demo, I had to create a new Trial instance (on the same tenant he already has) in French and without any “extra” modules, only the Sales one. Using Chrome, when I follow the process from https://trials.dynamics.com the trial is automatically created in English with all modules (including Field services and the others). Using Internet Explorer, I do have the choice of modules installed but also the language, currencies  and name… My laptop is in English does it have an impact here?

Zwei

Guido “Future Olive Farmer” Preite begged to differ:

I just created a new trial with Chrome and the wizard asked me the modules and the currencies. I used the link “Are you signing up on behalf of a customer or using this trial for development purposes? Sign up here.” (Option 2 here).

Ntathu

James Oleinik (the authority on the subject, in case it’s not clear) explains:

If you sign-up for a new trial from trials.dynamics.com and select one of the applications, then we have logic today that automatically select the language for your trial based on your browser locale. If you sign-up for a new trial from the Office admin center (or via the dev flow that Guido outlines), then you are presented an option to manually select the language for the trial.

Tîpp Jäår $0.02

If you need something other than Gẹẹsi then get your browser right, folks, it ain’t that hard.

Languages in a browser

(Social media cover photo by Jon Tyson on Unsplash)

Tip #1137: Learn language and study API to simplify your code

I already wrote about the benefits of learning new language features. Equally important is to understand what assemblies are available as part of Dynamics 365 SDK, how they work, what classes and interfaces are available, and how the edge cases work (basically, “what-if” scenarios, like “what if this is null”).

This week I had “privilege” to sink my teeth into some old code written by a developer with a particularly severe case of spießrutenlaufen. My eyes are still bleeding. Consider this fragment:

DateTime? DateAccepted = null;

if(entity != null) 
{ 
   DateAccepted = (entity.Contains("new_dateacc") 
   && entity["new_dateacc"] != null 
   && entity["new_dateacc"] != string.Empty) ?
   entity.GetValue<DateTime>("new_dateacc") 
    : (DateTime?)null;
}

I did some line wrapping for your viewing pleasure, original code was a one-liner. At this point in time you should be able to hear my eyes rolling all the way to the back of my head. How about this instead?

var DateAccepted = 
 entity?.GetAttributeValue<DateTime?>("new_dateacc");

There is no magic here, I simply used:

If you are unsure how things would work out if, for example, you used GetAttributeValue<DateTime>, why don’t you whip out some quick code to test the behavior:

As you can see, return seems to be default(T) for non-nullable T types. Yep, I’m using the goodness of LINQPad, a must have for every developer.

(Social media cover photo by Easton Oliver on Unsplash)

Tip #1136: How emails are resolved to the Dynamics 365 records

Literally a week later after Jonas “The Shuffler” Rapp was puzzled how From fields are resolved (see tip 1119),  Josh Wells from the cold city of Fargo (where some of the Microsoft folks tend to congregate) chimed in with the final resolution to the problem and a very good advice:

One of the best changes to Microsoft Docs is the fact that you can provide content feedback. You can do it within the article or at GitHub (scroll to the bottom of the article). This is an amazing opportunity for things like this to get changed or added into our documentation without having to go through different layers of providing input. With this said, I’ve gone ahead and filed this feedback within the following GitHub Issue for this article: https://github.com/MicrosoftDocs/dynamics-365-customer-engagement/issues/33

I would definitely encourage all of you to do the same when you see that documentation is lacking or needs further input.

Tîpp Jäår $0.02

The end result is a very succinct authoritative description of how emails are resolved. As we already mentioned, Microsoft Docs are now Open Source. And Josh is spot on: if you see something that you’re not happy about, do something about it.

(Facebook and Twitter cover photo by Clark Tibbs on Unsplash)

Tip #1135: For plugins, use SDK with the same or below the server version

Problem

Another week, another challenge from Guido “Future Olive Farmer” Preite:

I created a plugin for one Online instance (version 8.2.2.1862),  I created a class library project with .NET 4.5.2 and with nuget I installed the Microsoft.CrmSdk.CoreAssemblies version 9.0.2.3

I registered the plugin and I always get this error:

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: System.ArgumentNullException: Value cannot be null.

After checking the plugin code I decided to downgrade the nuget package to 8.2.0.2 and the plugin worked perfectly after. Beside the .NET 4.5.2, for Plugins, do we need to start to be careful to match the nuget version based on the Instance version? Or is it a bug in the latest SDK?

Solution

Nope, no bug, all is by design. You can’t get a more authoritative response than the one from Matt “SDK Deity” Barbour:

You cannot use a higher version of the SDK for a lower version of the server for plugins

Thus 8.x servers need to use 5 – 8.x assemblies. Where as 9.x servers need to use 5 – 9.x SDK assemblies.

(Facebook and Twitter cover photo by Alysa Bajenaru on Unsplash)

Tip #1134: Moving Users Between Business Units

As discussed in 917, moving Users between Business Units can be difficult and, as Joel suggested in 935, a good option when setting up a new system is to add a child Business Unit from the outset and add all the Users there. In a recent implementation I did not do this (in my defence, I did start the project before Joel wrote the tip.) So what do you do when you have ignored the Tips of the Day and are experiencing Spießrutenlaufen?

In my scenario I had 300 users to move to child Business Units. Also, as the change was driven by a security requirement, all Security Roles were changing. This was my approach.

First of all I needed to know who had what Security Roles. This can be done with the SSRS User Summary report which comes with Dynamics. You also will need to check whether any of your Teams have Security Roles assigned and whether these need moving and the consequences. In our case this was not a problem but, if it is, I would try Mitch Milan’s SnapShot! tool which is excellent for such things.

Exporting the User Summary report to Excel allows you to work out the ‘clusters’ of Users with the same security configuration. This means you can deal with groups of Users at once, which will save time. In my case this meant I was dealing with 90 clusters instead of 300 Users.

Once I knew the clusters, this is what I did:

  • I set up a tickbox on the User record called “User in Transition”
  • I created an On-Demand Workflow which toggled this tickbox
  • I created a User view which showed all Users with the tickbox ticked

Why so much effort? Because this gave me the most flexibility as you cannot do much with Users in an Advanced Find search, other than run a Workflow. In theory you could do it all from the Settings – Users screen but I liked the idea of the tickbox in case I got distracted and wanted to double check where I was up to.

This was the process:

  • Pick a cluster of Users (either handpicked in Settings – Users or via Advanced Find)
  • Run the Workflow against them
  • Go to Settings – Users and display the view of tickboxed Users
  • Change the Business Unit for the Users
  • Manage the Roles of the Users
  • Run the Workflow again to toggle off the tickbox
  • Confirm there are no Users in the tickbox view
  • Rinse and repeat

I am sure others will have suggestions for alternative approaches e.g. automation through scripting and the use of some of the excellent tools in the xRMToolbox so if you have ideas, put them in the comments section below.