Monthly Archives: October 2017

Dynamics 365: How do you get a column indexed automatically?

This seems to be another one of those “I used to think..”. In this case, I used to think that, once a column is added to the quick find view “find columns”, that column will be indexed automatically. Well, turned out it’s a bit more complicated; although, in the end, it’s probably still correct.

First of all, it would be worth looking at these two posts:

https://blogs.msdn.microsoft.com/darrenliu/2014/04/02/crm-2013-maintenance-jobs/

https://blogs.msdn.microsoft.com/crminthefield/2012/04/26/avoid-performance-issues-by-rescheduling-crm-2011-maintenance-jobs/

There is a bunch of useful information there, but what I was sort of missing is some low-level details. Yes, we can download Job Editor tool from codeplex; however, what is it, actually, going to do? The tool only works in the on-premise environment, and, from what I understand, it goes directly to the MSCRM_CONFIG database to update ScaleGroupOrganizationMaintenanceJobs table:

image

That table maintains the schedule of all those maintenance jobs per Operation Type per OrganizationId:

image

It seems that OperationType 15 corresponds to the Indexing Management job (I will explain why that’s important, just keep reading), even though there can be more than one job with that type (one per organization).

That said, here is how I got that index added to the table:

I created a new field on the entity

image

Then I added that field to the quick find columns

image

And, of course, published the changes.. on the database side, there was still no index:

image

So, I downloaded the tool and tried to reschedule the indexing job. That did not quite work out.. The job got rescheduled, but not for the date for which I wanted it (I wanted to see if the index gets created.. so I actually wanted that job to run almost immediately. Instead, it kept moving 1 day forward every time I would try to reschedule it using the tool)

Eventually, I just went to the SQL Management Studio and ran this SQL query:

UPDATE ScaleGroupOrganizationMaintenanceJobs

SET NextRunTime = ‘2017-11-01 02:10:00’

WHERE id=’…’

(If you ever need to run the same query, make sure you change the id and, also, the date.. that date should be in UTC)

The I restarted the Async Services (both, though it may be sufficient to restart the “maintenance” one), and voila.. There is an index now:

image

Sure you can do this only in the on-premise environments, and only if you have required permissions on the SQL server. However, normally we would not need it. What we should probably keep in mind (as a result of this exercise) is that:

  • Yes, indexes are created when a field is added to the “find columns”
  • No, they are not created right away – there is a scheduled job that is running daily
  • If you are working in the on-premise environment, you may be able to reschedule that job. If you are working in the online environment, you may just have to wait

PS. And, if I had full-text search enabled, this whole story would be different.. but that’s for another post.

Dynamics 365: Working with the virtual entities

It seems the basics of the Virtual Entities have been covered in the blog post below while this feature was still in the preview:

https://blogs.technet.microsoft.com/lystavlen/2017/09/08/virtual-entities/

Now that we do have it in V9, it seems that one major issue that will be limiting our ability to use Virtual Entities in the real-life scenario is security because Virtual Entities are organization-owned, so they cannot be really controlled by the Dynamics security.

Every CRM user will either be able to see all or nothing – from the integration perspective, that’s almost never going to work.

I wanted to explore, then, if there is an option to limit access to the virtual entities with the help of the RetrieveMultiple plugins, and that’s what this post is going to be about.

To start with, let’s create a virtual entity as described in the post above.. while doing this, keep in mind that, once you have the data source and the virtual entity, you still need to map the fields. If you don’t do that, you’ll get the following error message:

image

Entity could not be retrieved from data source. Please try again or contact your system administrator

If you see that error message, make sure you did configure field mappings:

image

So, make sure to configure the external names, and you should be able to see this:

image

If you look at the security role configuration, the only 3 permissions you’ll be able to give on that new entity are Read/Append/AppendTo (all on the organization level):

image

So, yes, we are allowed to set up relationships between virtual entities and other entities.. Although, when setting up a 1:N between a native entity and a virtual entity, we have to provide an external name for the lookup field:

image

Which makes sense since there has to be a lookup on the “N” side of the relationship.

Either way, at this point there is a Virtual Entity but there is, basically, no security. By the way, we are, actually, allowed to build SSRS reports for the virtual entities:

image

So that turns the original question of whether we can use a plugin to introduce some security into a somewhat more complicated one.. Since RetrieveMultiple plugins do not work for SSRS reports, even if we can make that plugin work for the Virtual Entity, can we also make it work for the SSRS reports?

In theory, if we can use a plugin, then we can, probably, comes up with a custom security model. But developing a complete solution is not the purpose of this post – really all I wanted to do is to see whether I can use a plugin to start with. Let’s see then..

Here is my plugin code:

using System;
using System.Activities;
using System.Collections;
using System.Xml.Linq;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.Collections.Generic;
using System.Data;
using System.Linq;
            
namespace VETest
{
    public class RetrieveMultiple: IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService =
                (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            if (context.OutputParameters.Contains("BusinessEntityCollection"))
            {
                var results = ((EntityCollection)context.OutputParameters["BusinessEntityCollection"]).Entities.ToList();
                
                List updatedResultList = new List();
                foreach (Entity entity in results)
                {
                    if (entity.Contains("tcs_name") && (string)entity["tcs_name"] != "Early morning start, need coffee")
                    {
                        updatedResultList.Add(entity);
                    }
                }
                context.OutputParameters["BusinessEntityCollection"] = new EntityCollection(updatedResultList);
            }
        }
    }
}

The idea is that, in the post-operation RetrieveMultiple, the plugin will go over the list of records returned from the datasource and will remove some of them from the results. In this particular case,  a record with that particular value in the “name” field will be removed.

So, I got the plugin compiled, and here is how the steps has been registered:

image

You can do all of the above using XrmToolBox, btw. Just use CodeNow plugin to compile the plugin, and, then, use Plugin Registration plugin in XrmToolBox to register the plugin (that’s a lot of plugins in one sentence..) I’m using tcs_name attribute in that code, though, and that’s something you may need to change first.

Turns out, the plugin works just fine. There is only 1 record in the results now:

image

Surprisingly, there is only 1 record in the report as well:

image

That last one makes it an interesting precedent, btw. I am wondering if all other SSRS reports will, eventually, go through the standard retrieve pipeline when querying  data from Dynamics.. that would remove one of the important limitations we have now when using RetrieveMultiple for custom security.

Either way, it seems that it is possible to customize Virtual Entity security with the help of RetrieveMultiple plugins. Of course what I did above was a very simple example.. Nothing but a proof of concept, really. But it worked, and, it turned out, it also worked with SSRS, so, at the very least, we have a workaround – such a workaround will, likely, involve quite a bit of development, but that’s a different story.

Dynamics 365: SDK 9.0 assemblies are available now

While we still cannot download complete V9 SDK for Dynamics 365, I just noticed that Nuget packages for V9 are available now. So those of us who need SDK assemblies to develop plugins/applications can now install those packages:

image

There will likely be other new features there,  but one of those which would not be available in the earlier versions of the SDK is a new type for the Multi Select Option Sets:

Microsoft.Xrm.Sdk.OptionSetValueCollection

It’s, basically, a collection of OptionSet values, so there are all the usual collection methods/properties there which we can now use to work with the Multi Select Option Set attributes.

Dynamics 365: Lookup controls – which view is the “lookup view”?

I used to think that lookup controls are using entity “lookup view”, but, it seems, I was wrong. It might be something that has changed along the way, or it might always work differently.. this way or another, it came out as a bit of a surprise earlier today when I was looking at V9.

Basically, when setting up a lookup control, there is an option to choose the default view.

image

It seems that’s exactly the view which Dynamics will be using as a lookup view.

Yes, it is definitely the view that shows up when I click “Look Up More Records” – that I knew:

image

 

image

What I did not quite realize, though, is that it’s the view which Dynamics is using as a lookup view when we start typing in the lookup control, for example:

image

Just have a look at the columns in my “accounts lookup view” and you’ll see that it’s not that view at all – there are no emails on the screenshot above, but it’s the second column in the lookup view:

image

 

Actually, it seems to be a bit more complicated than just searching in the default view. The way I understand it, here is what Dynamics will do once you have typed in a search string in the lookup control and clicked the search button:

  • It will apply default view filtering conditions first
  • It will extend those conditions with the “OR” filter on all the attributes added to the “find columns” of the lookup entity’s quick find view
  • It will use default view column layout to display the results (3 first columns of the view will be displayed)

 

And it seems to be somewhat consistent with the description here:

https://www.microsoft.com/en-US/dynamics/crm-customer-center/how-inline-lookup-works.aspx

Although, I’m not sure what it means when it’s been put this way:

“Lookup search results show the first three columns that are defined in the lookup view of the entity or the view that’s set as the default view of that lookup”

Based on the screenshots above, it seems that Dynamics will be using “default view” only.

Dynamics 365: Action Steps public preview – can we customize opportunity close window now?

 

There is an interesting new feature available in the public preview now:

image

You will find more details on what other feature are available if you look at this blog post:

https://blogs.msdn.microsoft.com/crm/2017/10/25/new-automation-and-visualization-features-for-business-process-flows-public-preview/

When I saw the description of the action steps there, here is what I wanted to try right away(custom opportunity close dialog):

image

And it would work just fine if I could reload the form after this action has executed which, it seems, I cannot do right now, so the opportunity keeps showing up as an “open” opportunity until the screen has been refreshed manually. I’m pretty sure we can find an unsupported way to attach some javascript there, but would not it be nice to have it all supported out of the box?

Either way, if you want to see this feature in the next release, and, possibly, if you wanted to add other comments, here is a link you can use to vote for the idea that’s been already submitted to the idea portal:

Bring Action Steps to GA

Dynamics 365: Users Without Security Roles

In the 9.0 version of Dynamics 365 we can now use “does not contain” condition (which is, basically, “does not exist”) on the related records:

http://www.itaintboring.com/dynamics-crm/v9-accounts-that-have-no-opportunities-almost-there/

So this is what I tried when I wanted to see all users without any security roles:

image

This, however, produced an error:

image

To use this saved view, you must remove criteria and columns that refer to deleted or non-searchable items

It is not the clearest error message, but, it seems, the problem is somehow related to the N:N relationships of the SystemUser entity. The same happened when I tried to find all users without teams.  But it worked just fine when I tried to find contacts not linked to leads (through the N:N there). Actually, I tried leaving only the”fullname” attribute in the view – it still did not work, and I am pretty sure fullname is searchable.

So, how do you find users without security roles?

It’s easy to do. Just go to Settings->Security->Users, and select an out-of-the-box “Users with no assigned security roles” view:

image

Interestingly, that view is not editable(you cannot edit the filter when looking at it from the customizations area), and it’s not even selectable in the Advanced Find from the “Use Saved View” dropdown. In other words, you can’t do much about that view other than to see the results when you go to that particular area in Dynamics, but, on the other hand, you don’t need it that often either way. Just need to remember it’s thereSmile

Dynamics 365: How do you deactivate a business process and unlink it from existing records?

Imagine that you had a business process enabled on the entity, and it has already been activated on a number of records. For example, here is a case record for which I have activated a business process:

image

What if you wanted to completely deactivate that business process (and, also, detach that business process from the case record above)?

The first step would be to go to the solution file and to deactivate the process there:

image

The interesting part, though, is that it would not be sufficient. You would still see that business process associated with the record, even though there would be a warning message notifying you that the business process has been deactivated:

image

So how can you get rid of the business process “completely”?

Turns out it’s not, actually, that complicated. Since every process has a corresponding entity, you can simply use advanced find to find all instances of that process entity:

image

And delete them:

image

And there you go – the same case record does not have a process linked to it anymore:

image

Known Issues in V9

I’m not sure I’ve ever seen this kind of comprehensive “known issues” page for the earlier releases of Dynamics 365/CRM, but it’s definitely worth looking at just so you are aware of some of the issues you may run into in V9:

Dynamics 365 Customer Engagement General Availability Readme (Known Issues)

I just tried reproducing a couple of those issues on my trial instance of V9, and, it seems, at least some of them may have been fixed:

  • I was able to create a dynamic marketing list
  • I was able to add a custom view to the account entity

But, for example, a multi-select option set does show up in the edit mode all the time (in the unified interface)

In other words, it’s possible that some of those issues are being worked on/have been fixed.. But, if you run into something that does not look normal, have a look at that page above – it might be a known issue in this first release of V9.

That said, it’s interesting to look at those issues in perspective. Some of them are happening on IPod, others are happening on Android devices, there are issues happening in the Internet Explorer, and there are yet other issues happening in Firefox.. Some of them are happening in Edge/Firefox/IE 11, but, it seems, not in Chrome. Etc etc.. It seems Dynamics has become a bit of a victim of its own success this time around – there are so many environments it has to work in that it’s almost impossible to make it issues-free everywhere. Well, I’d love it to be issues-free, but, it seems, I can understand why it’s not.. yet:)

So, be aware of those known issues, and enjoy 365-ing!

 

 

 

Dynamics 365: Implementing on-save confirmation dialog with Alert.js

We can make some fields required and we can make other fields optional.. But what about all those not so black-and-white situations where the system may still be able to warn the users about some possible inconsistency in the data, but the user should still be able to override that warning?

There are different options we can use to make this work, but one of them would be to display a warning message form the on-save.  That means we would need to do a few things:

  • Add an on-save handler
  • Display a warning message
  • Allow the user to click “ok” or “cancel” in that message
  • If the user clicks “ok”, we should still save the record
  • And we will likely need to disable autosave, at least in that particular OnSave handler

 

Here is what I ended up with:

image

And here is what I had to do to get it to work:

Step 1: Download alert.js and install the solution

First, I went to the  alert.js github page ( Alert.js ) and downloaded the solution from there:

image

Step 2: Add a web resource

Then, I’ve added the following script to a web resource:

var isConfirmed = false;
function onSave(executionObj)
{
  var eventArgs = executionObj.getEventArgs();
  if(eventArgs.getSaveMode() == 70)//AUTOSAVE
  {
    eventArgs.preventDefault();
    return;  
  }

  var condition = Xrm.Page.getAttribute("name").getValue() == "123";//If not “123”, display a confirmation 
  if(!condition && !isConfirmed)
  {
    eventArgs.preventDefault();
    Alert.show("This is not a 123 account", "Are you sure you want to save the changes?", [
         new Alert.Button("Save", confirmCallback, true),
         new Alert.Button("Cancel")  
         ], "WARNING");
  }
  else
  {
    isConfirmed = false;//Reset the flag for the next save
  }
}

function confirmCallback()
{
  isConfirmed = true;//to make sure we don't display alert dialog from onSave this time
  Xrm.Page.data.save(); 
}


Step 3: Add web resources to the form

After that, I’ve added my new web resource to the form together with the Alert.js web resource:

image

Step 4: Configure OnSave handler for the form

image

Step 5: Save, Publish All, and Run a test

image

That was quick and easy!

But I still wanted to clarify a couple of things

Alert.show call does not block javascript execution. That’s the reason there is a call back function there, and there is a call to Xrm.Page. data.save() from that callback.

And I needed that additional isConfirmed boolean variable so the script would not display the confirmation dialog every time.

Happy 365-ing!