Adding Items to a Dynamics Queue

Continuing off my post of adding items to a queue programmatically, I wanted to add items to this queue (why else would I be using a queue?).

The code here is relatively simple and boring as I queried for a contact named Andrew, found him and added a new queueitem to the queue.

QueryExpression queryContact = new QueryExpression();
queryContact.EntityName = "contact";
queryContact.ColumnSet = new ColumnSet(true);
queryContact.Criteria.AddCondition("firstname", ConditionOperator.Equal, "Andrew");

EntityCollection entityContacts = _CrmService.RetrieveMultiple(queryContact);
EntityReference contactRef = new EntityReference("contact", entityContacts[0].Id);

Entity q = new Entity("queueitem");
q["queueid"] = new EntityReference("queue", _QueueId);
q["objectid"] = contactRef;
_CrmService.Create(q);

The results were anything but.

The first time I executed this code it worked fine, created a new queueitem record and associated to my man Andrew.

The second time I executed this code, it exploded with the following message (which seems odd for a queue to do).

Picture (Device Independent Bitmap) 1

So then I went to the contact record itself, tried to do this manually, but this time I received no error.  When I checked the queue though, it only had one instance of my queueitem in there.

Still perplexed, I then created a phone call activity, added my contact to it, then added that to the queue (multiple times) and this worked fine (and showed multiple instances in the queue).

Perhaps there is a difference between how Dynamics handles core entity interactions vs activities.  I find it odd that this restriction exists because every record goes into the queue as a unique queue item.  For what I was trying to achieve (logging changes to records, not activities, in the order they were processed) this was not going to work.

Unfortunately, I haven’t found a way around this functionality to disable it.  If anyone knows the reason, I would love to hear the why behind it.

 

Accessing Dynamics Queues Programmatically

I typically still code in Dynamics using LateBound requests.  There have been a few instances where I have switched to Early Bound but I continue to do this for the following reasons

  1. I don’t like dragging around proxies into my code that can change environment to environment.
  2. When not depending on proxies, I feel have more options to downgrade my code into different versions based on what can be discovered.
  3. I get to learn about all the hidden relationships between entities and attributes that gives me a deeper understanding of what lies beneath.

With that said, this week I needed to access some queues in Dynamics and see what was in them.

To do this, I queried Dynamics for my queue based on the name provided.

QueryExpression query = new QueryExpression();
query.EntityName = "queue";
query.ColumnSet = new ColumnSet(true);
query.Criteria.AddCondition("name", ConditionOperator.Equal, "MySuperQueue");

EntityCollection entityResults = _CrmService.RetrieveMultiple(query);

From here, I was then able to query the queue for what it contains.

if (entityResults.Entities.Count == 1)
{
_CrmQueue = entityResults[0];

_QueueId = new Guid(_CrmQueue["queueid"].ToString());

QueryExpression queryQueues = new QueryExpression();
queryQueues.EntityName = "queueitem";
queryQueues.ColumnSet = new ColumnSet(true);
queryQueues.Criteria.AddCondition("queueid", ConditionOperator.Equal, _QueueId);

EntityCollection entityQueues = _CrmService.RetrieveMultiple(queryQueues);

foreach (Entity ent in entityQueues.Entities)
{
System.Diagnostics.Debug.WriteLine(ent["title"].ToString());
System.Diagnostics.Debug.WriteLine("ENTERED ON: " + ent["enteredon"].ToString());
if (ent.Contains("workeridmodifiedon"))
{
System.Diagnostics.Debug.WriteLine("BEING WORKED ON: " + ent["workeridmodifiedon"].ToString());
}

}
}

I’ll write another post on how to add an item to a queue, because that prevented some logic and general understanding of queues headaches that through me for a loop.

The key fields I want to highlight here are enteredon and workeridmodifiedon (both returning datetime values.  If you are managing a queue, enteredon is the datetime that the item was added to the queue and workeridmodifiedon is the much more important value that shows when the item as picked to be worked on.

A sad fact about Dynamic/CRM queues – all those fancy actions of Pick/Remove/Release – do not change the state of the queueitem in Dynamics which can present for some interesting challenges (a topic for another post).  I have to believe that interfacing with queues would be that much more robust if the status reasons changed as a result.

For now, now you know how to access the items in your queue from your own code.

Creating a Custom Interactive button in Dynamics

It’s been awhile since I played with the Ribbon Workbench and I had to re-familiarize myself with it to deploy some custom button functionality to a Dynamics tenant.

If you’re not familiar with the Ribbon Workbench, go download it and bask in it’s glory and time saving capabilities.

Once you install the solution into your Dynamics system, usage is as simple as selecting the solution you want your new button to be deployed to, dragging a button onto the Form toolbar and creating a command object that calls a function in your specified JavaScript file.

Creating the Button

As you can see from the screenshot, my function is called SendMail and called from a library within the provided file.  When I first started coding this button, I added a simple alert() to the initial function call so I could quickly validate the buttons functionality, deploy it and move on to the rest of the implementation.

Capture

There are a host of other options in creating a button related to display rules and Hide actions which can make your implementation that much more dynamic.

What I really like about the Ribbon Workbench is that the customizations are deployed directly to your solution without having to deploy the workbench solution between environments.

No external Dependencies = awesome development!

User Interaction

In my scenario, the button that I created was calling an action where the results were passed back to my calling function – for better or for worse.

Adding to my integration, I sent a notification back to the client when the action had completed.  If there was an error, the error was sent to the client.

For an Informative warning this looked like.

Xrm.Page.ui.setFormNotification("Authorization successfully sent.", "INFORMATION");

And in the case of an error.

 function (e) {
 // Error
 console.log("Workflow Err: " + e);
Xrm.Page.ui.setFormNotification("Could not Authorize, Error: " + e, "ERROR");
 }

When both solutions are thrown together, a great integration story for facilitating calls to a custom service, action or workflow and updating users on the status of those calls when completed.

Improve Query Performance to Oracle

I recently had an issue where we were migrating a large Oracle database into Dynamics which required a significant amount of lookups back to Oracle for synchronization keys between both systems.

When we moved the system between different database environments we started to see the following errors.

“ORA-12801: error signaled in parallel query server P001\nORA-12853: insufficient memory for PX buffers: current 1632K, max needed 80640K\nORA-04031: unable to allocate 65560 bytes of shared memory (\”large pool\”,\”unknown object\”,\”large pool\”,\”PX msg pool\”)”  

As a developer, I get very worried when code changes are required between environments when all other variables stay the same (i.e., database, code, etc).  In this case however, we had been lucky that we had not run into this problem in DEV.

Where I was dynamically constructing the query on the fly, Oracle saw this as a new query being built every time (despite the only thing changing was the value in the WHERE Clause).  On their own these queries were fine, but when running about 50,000+ lead to some issues.

To get around the above error we leveraged the OracleParameter syntax as follows.

OracleCommand oraCommand = new OracleCommand("SELECT user FROM test.USER_LOOKUP WHERE user = :userName", db);
oraCommand.Parameters.Add(new OracleParameter("userName", userId));

Once implemented, we noticed a huge shift in performance and no more parallel query errors.  We had a lot of classes to change but were able to implement the change in a little under a day.

A Scaled out CRM Solution Architecture

Recently I started work on a pretty big CRM project and I wanted to apply a more scaled out approach to my solution architecture.  CRM offers a great facility to deploy code in their solutions but when starting a new project you should always ask yourself the following questions before you starting adding entities into your solutions.

  1. What is the frequency of updates that will be requested by the users and to what components?
  2. Are there multiple users contributing to this project?
  3. How big do you expect this project to grow by?
  4. What kind of promotional model is in place for deployments?

I  have found that questions such as these generally drive the overall solution architecture I will put in place on a project.  For instance, if we are working with a client that has a Development to Production promotion model with only a developer or two on the project, I’ll suggest deploying as one solution.  However, if the project is quite large, has multiple developers on it coupled with multiple deployment stages (which invariably means a more formalized testing process) I’ll tend to go with a more scaled out architecture.

For this current project I went with a component based solution architecture broken out as follows;

  1. Entities – this contains all my core entities, client extensions and web resources.
  2. Security – this contains all my security roles.
  3. Reports – this contains all my custom reporting files.
  4. Workflows – this contains all custom workflows and plugin functionality.

The reason for this approach is to reduce the load on QA and allow the team to install what they need without fear of interfering with the work of others.

sol

Some scenario examples where this should help the team;

  1. When a developer makes a change to only 1 of the solutions, QA can rest easy deploying that single solution (instead of all 4) and not having to regression test all 4 but only 1 solution.
  2. Reports will most likely be handled by developers that are very familiar with developing custom RDL files, as such, they don’t need references to any of the underlying entities and based on user feedback, they will be able to deploy on their own schedule, outside of the core application.
  3. Having security in it’s own solution now opens this up to being managed by non-developer groups (huge).  Although I don’t recommend deploying an unmanaged solution to Production, this solution can actually start it’s “development” or “work” in a TEST or UAT where Business Analysts can create the security roles they think make sense against the new components built by the developer teams without worrying about interfering with any previous development to date.

These are only a few scenarios where I see this architecture helping out in the long-run.  I have gone through a couple of iterations of scaled out architectures from feature to product based but so far this one represents a consistent approach that can be replicated across projects.

My next step will be to minimize any complexity associated with deploying updates to different environments by writing a little component to deploy the correct solution in the correct order.  However as it stands right now, the solutions themselves are quite loosely coupled and can be deployed without error (i.e., reports) without triggering a solution import error.

Creating a New area in CRM 2015 – By Hand

Emphasis on the “By Hand”.  I’d previously blogged about how to modify the Site Map in Dynamics365 with some of the new  ribbon editing features very reminiscent of Ribbon Bench (here for reference Site Maps and Custom Entities – Oh My!) – but recently had the pleasure of having to do this in 2015, with no tools.

The modification of the XML customizations.xml file itself wasn’t too bad on it’s own, where things really became complicated was when I wanted to add an image to my area.

Modifying the Customizations.xml File

To create your new Groups and Areas – check out this post that does a great job of walking you through how to export, modify and import the XML file (along with screenshots).

Adding an Image to your Area

Now where things went off the handle was when I wanted to add an image to my new area.  In order to do this correctly, you need to ensure that the following values all line up exactly including the case and extension.  After banging my head against the wall I noticed that my URL for my web resource did not necessarily have the same display name and some of what it was mixed case.  So I deleted the image, re-uploaded and made sure that all three fields highlighted below.

ImageEdit.PNG

Lined up with the name being entered here.

ImageEdit2.PNG

After I did this, my solution was again able to import without issue and the image was now being consumed.  Let CRM add in your publisher information, no need to modify that.  After having figured this out, I was able to go back and update the image without issue.

Hopefully this saves you some time.