Posted on 15. March 2017

Limitations of Calculated Fields and the Data Export Service

You probably already know that I'm a big fan of the Data Export Service. The single fact of having a 'near real time' replica of your data in a SQL Azure Database to query in any way you want is simply amazing.

Today I came across an interesting limitation with Calculated Fields. Although Calculated Fields are created in the Dynamics database as SQL Server Computed Columns, they are output in the Replica Database fields as standard fields.

This has a rather inconvenient side-effect when you have calculated fields that are linked to either date/time or a related record. Since the Azure Replica sync is event based, when a related record is updated there is no corresponding event on the referencing record that contains the calculated field therefore it does not get updated. Likewise, if a calculated field changes depending on the date/time then there is no event that triggers the azure replica to be updated. This means that although calculated fields maybe correct at the time the record was created, subsequent updates can make the field become stale and inaccurate.

Lesson learned - you cannot guarantee the accuracy of calculated fields in the Azure Replica if they contain:

  1. The Now() function
  2. A related record field (e.g. accountid.name)

Interestingly, calculated fields that use data on the same record do get updated, so the event integration must do a compare of any calculated fields to see if they have changed.

@ScottDurow

Posted on 14. March 2017

There is something rather different about Dynamics 365 Business Process Flows!

The new business process flow designer in Dynamics 365 is lovely! However, I'm not going to talk about that since it's rightly had lots of love by others already.

For me the biggest change in Dynamics 365 is the fact that running Business Process Flows (BPFs) are now stored as entity records. Instance details are no longer held as fields on the associated record. I first visited this topic back in the CRM2013 days with the introductions of Business Process Flows where I described how to programmatically change the process.

Previously when a BPF was started, all of the state about the position was held on the record it was run on was stored in fields on the record itself:

  • Process Id: The ID of the BPF running
  • Stage Id: The ID of the BPF step that was active
  • Traversed Path: A comma separated string listing the GUIDs of current path of steps taken through the BPF. This is to support BPFs with branching logic.

With the new Dynamics 365 BPFs, each process activated is automatically has an entity created that looks just like any other custom entity. The information about the processes running and any record is now stored as instances of this entity with a N:1 relationship to the parent record and any subsequent related entities. This BPF entity has similar attributes that were stored on the parent entity, but with the following additions:

  • Active Stage Id: The ID of the BPF step that is active – replaces the Stage Id attribute.
  • Activate Stage Started On: The Date Time that the current step was started on – this allows calculation of the amount of time it has been active for
  • State & Status: Each BPF Instance has its own state that allows finishing and abandoning before other BPF are run.

     

In addition to making migration of data with running BPFs a little easier - this approach has the following advantages:

  1. You can control access to BPFs using standard entity role privileges
  2. You can have multiple BPFs running on the same record
  3. You can see how long the current stage has been active for
  4. You can Abandon/Finish a BPF

BPF Privileges

Prior to Dynamics365, you would have controlled which roles could access your BPF using the Business Process Flow Role Check list.     In Dynamics 365 when you click the 'Enable Security Roles' button your BPF you are presented with a list of Roles that you can open up and define access in the 'Business Process Flow' tab:

Multiple BPFs on the same record

Switching BPFs no longer overwrites the previous active step – meaning that you can 'switch' back to a previously started BPF and it will carry on from the same place. This means that BPFs can run in parallel on the same record.

  • If a user does not have access to the running BPF they will see the next running BPF in the list (that they have access to).
  • If the user has no access to any BPF that is active – then no BPF is shown at all.
  • If user has read only access to the BPF that is running, then they can see it, but not change the active step.
  • When a new record is created, the first BPF that the user has create privileges on is automatically started.

When you use the Switch Process dialog, you can now see if the Business Process Flow is already running, who started it and when it was run.

NOTE: Because the roles reference the BPF entities – you must also include the system generated BPF entities in any solution you intend to export and import into another system.

Active Step timer

Now that we have the ability to store addition data on the running BPF instance, we have the time that the current step was started on. This also means that when switching between processes, we can see the time spent in each step in parallel running BPFs.

Abandon/Finish

Since each BPF has its own state fields, a business process can be marked as Finished – or Abandoned at which point it becomes greyed out and read only.

When you 'Abandon' or 'Finish' a BPF it is moved into the 'Archived' section of the 'Switch Process' dialog.

NOTE: You might think that this means that you could then run the BPF a second time, but in-fact it can only have a single instance per BPF – and you must 'Reactivate' it to use it again.

  • Reactivating an Abandoned BPF will start at the previously active step
  • Reactivating a Finished BPF will start it from the beginning again.

Example

Imagine your business has a sales process that requires an approval by a Sales Manager. At a specific step in that sales process you could run a workflow to start a parallel BPF that only the Sales Managers have access to. When they view the record, making the Approval BPF higher in the ordered list of BPFS will mean that they will see the Approval BPF instead of the main Sales Process. They can then advance the steps to 'Approved' and mark as Finished. This could then in turn start another Workflow that updates a field on the Opportunity. Using this technique in combination with Field Level Security gives a rather neat solution for custom approval processes.

When I first saw this change I admit I was rather nervous because it was such a big system change. I've now done a number of upgrades to Dynamics 365 and the issues I found have all been resolved.
I'm really starting to like the new possibilities that Parallel BPFs brings to Dynamics 365.

@ScottDurow

Posted on 11. March 2017

Simplified Connection Management & Thread Safety (Revisited)

There is one certainty in the world and that is that things don't stay the same! In the Dynamics 365 world, this is no exception, with new features and SDK features being released with a pleasing regularity. Writing 'revisited' posts has become somewhat of a regular thing these days.

In my previous post on this subject back in 2013 we looked at how you could use a connection dialog or connection strings to get a service reference from the Microsoft.Xrm.Client library and how it can be used in a thread safe way.

Microsoft.Xrm.Tooling

For a while now there has been a replacement for the Microsoft.Xrm.Client library – the Microsoft.Xrm.Tooling library. It can be installed from NuGet using:

Install-Package Microsoft.CrmSdk.XrmTooling.CoreAssembly

When you use the CrmServerLoginControl, the user interface should look very familiar because it's the same that is used in all the SDK tools such that Plugin Registration Tool.

The sample in the SDK shows how to use this WPF control.

The WPF control works slightly differently to the Xrm.Client ShowDialog() method – since it gives you much more flexibility over how the dialog should behave and allows embedding inside your WPF application rather than always having a popup dialog.

Connection Strings

Like the dialog, the Xrm.Tooling also has a new version of the connection string management – the new CrmServiceClient accepts a connection string in the constructor. You can see examples of these connection strings in the SDK.

CrmServiceClient crmSvc = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);

For Dynamics 365 online, the connection would be:

<connectionStrings>
    <add name="Xrm" connectionString="AuthType=Office365;Username=jsmith@contoso.onmicrosoft.com; Password=passcode;Url=https://contoso.crm.dynamics.com" />
</connectionStrings>

Thread Safety

The key to understanding performance and thread safety of calling the Organization Service is the difference between the client proxy and the WCF channel. As described by the 'Improve service channel allocation performance' topic from the best practice entry in the SDK, the channel should be reused because creating it involves time consuming metadata download and user authentication.

The old Microsoft.Xrm.Client was thread safe and would automatically reuse the WCF channel that was already authenticated. The Xrm.Tooling CrmServiceClient is no exception. You can create a new instance of CrmServiceClient and existing service channels will be reused if one is available on that thread. Any calls the same service channel will be locked to prevent thread issues.

To demonstrate this, I first used the following code that ensures that a single CrmServiceClient is created per thread.

Parallel.For(1, numberOfRequests,
    new ParallelOptions() { MaxDegreeOfParallelism = maxDop },
    () =>
    {
        // This is run for each thread
        var client = new CrmServiceClient(username,
               CrmServiceClient.MakeSecureString(password),
               "EMEA",
               orgname,
               useUniqueInstance: false,
               useSsl: false,
               isOffice365: true);
        
        return client;
    },
    (index, loopState, client) =>
    {
        // Make a large request that takes a bit of time
        QueryExpression accounts = new QueryExpression("account")
        {
            ColumnSet = new ColumnSet(true)
        };
        client.RetrieveMultiple(accounts);
        return client;
    },
    (client) =>
    {
    });

With a Degree of Parallelism of 4 (the number of threads that can be executing in parallel) and a request count of 200, there will be a single CrmServiceClient created for each thread and the fiddler trace looks like this:

Now to prove that the CrmServiceClient handles thread concurrency automatically, I moved the instantiation into loop so that every request would create a new client:

Parallel.For(1, numberOfRequests,
    new ParallelOptions() { MaxDegreeOfParallelism = maxDop },
    (index) =>
    {
        // This is run for every request
        var client = new CrmServiceClient(username,
               CrmServiceClient.MakeSecureString(password),
               "EMEA",
               orgname,
               useUniqueInstance: false,
               useSsl: false,
               isOffice365: true);
        // Make a large request that takes a bit of time
        QueryExpression accounts = new QueryExpression("account")
        {
            ColumnSet = new ColumnSet(true)
        };
        client.RetrieveMultiple(accounts);
    });

Running this still shows a very similar trace in fiddler:

This proves that the CrmServiceClient is caching the service channel and returning a pre-authenticated version per thread.

In contrast to this, if we set the useUniqueInstance property to true on the CrmServiceClient constructor, we get the following trace in fiddler:

So now each request is re-running the channel authentication for each query – far from optimal!

The nice thing about the Xrm.Tooling library is that it is used exclusively throughout the SDK – where the old Xrm.Client was an satellite library that came from the legacy ADX portal libraries.

Thanks to my friend and fellow MVP Guido Preite for nudging me to write this post!

@ScottDurow