Custom Translations – the Easy Way

In many customer projects and products, I have built solutions for managing translations in Microsoft Dynamics 365 / CDS / CRM.
Sure, the metadata can be translated to show labels etc in the language of the user, but having a custom solution for translations ensures localized content for texts that are shown to the user from code or automation.

Continue reading “Custom Translations – the Easy Way”

Create view: Active Contacts in My State

Microsoft Dynamics 365 Customer Engagement and Common Data Service offer us the querying language FetchXML to retrieve data. Since this is the language used for views saved in the system, we can use FetchXML Builder for XrmToolBox to alter the features of views beyond what is possible using platform features, without making them unsupported.

Continue reading “Create view: Active Contacts in My State”

FetchXML Builder and Friends at D365UG Virtual Summer Camp

On August 7-9, the first ever Virtual Summer Camp for the Dynamics 365 platform will take place.

During this free event the D365UG offer some 30+ sessions with focus on Customer Service and Field/Project Service.

I will be doing one of a few cross vertical sessions, where I discuss and demonstrate some useful XrmToolBox tools that help customizers, administrators and users with information analysis and enhancing the capabilities of the system.

Below is a description of my session – enjoy and make sure you sign up! Click the link: D365UG Virtual Summer Camp

Continue reading “FetchXML Builder and Friends at D365UG Virtual Summer Camp”

FetchXML Builder for Microsoft Dynamics 365/CRM got an extreme makeover

 

The first release of FetchXML Builder for XrmToolBox in 2018 contains a major face-lift.

New year – new design! After more than three years since first release, the time has come to use all the feedback from issues on GitHub, comments on Twitter, and collected statistics to improve the UI. This article describes some of the major changes introduced with the first release of 2018.

Continue reading “FetchXML Builder for Microsoft Dynamics 365/CRM got an extreme makeover”

CRM Saturday – XrmToolBox with Jonas Rapp

CRM Saturday is a recurring event where Microsoft Dynamics CRM/365 experts and MVPs gather for a day filled with sessions from both strategic and technical perspectives on everything from user adoption to plugin unit testing to IoT and intelligent analysis.

On Saturday January 28 the event was held in London, UK at the Microsoft offices in Paddington. As a “senior contributor” to the world famous XrmToolBox by MVP Tanguy Touzard I was invited to do a session on simplifying development using XrmToolBox. image My session covered a brief XrmToolBox background, examples of my own favorite tools, and deep dive demos of FetchXML Builder and Plugin Trace Viewer. Of course you cannot do a demo with some customizations and plugins without using a few other XrmToolBox tools, so I did not only cover my own block busters… The presentation from the event is now available here: CRM Saturday – XrmToolBox with Jonas Rapp This contains the full presentation, and also step by step details on the demos performed, as well as some bonus demos that did not fit the tight session schedule. Note that the presentation also contains reference to a free to use GitHub repository with a simple plugin base class, that can be inherited instead of simply implementing the SDK interface IPlugin to greatly simplify plugin development and logging to the Tracing Service. The repository is available here: https://github.com/rappen/JonasPluginBase

If you would like to dig even deeper into the tracing service, XrmToolBox and the Plugin Trace Viewer – join me on my session on this topic during eXtreme365 for Partners in Lisbon, Portugal that takes place March 13-15 2017 !

  If you have any questions regarding the presentation, demo or the plugin base class, don’t hesitate to contact me!   More information on CRM Saturday: http://crmsaturday.com
More information on eXtreme365: http://extremecrm.com

Show hierarchically related activities in subgrid

In this article I will demonstrate how to implement a plugin to extend the possibilities for showing activities that are related through account hierarchy in a subgrid on a Microsoft Dynamics CRM form.

In my previous article I showed how to create a simple plugin to show all directly related activities in a subgrid, and not just activities related through the Regarding field.

Objective

The goal is to be able to display all activities (yellow boxes) anywhere below any account (blue box) that is opened in CRM. Some of you may recognize this model – it is respectfully borrowed from MVP Jukka Niiranen’s blog post on this problem: CRM 2011 subgrids ain’t what associated views used to be. As this article indicates, this has been a problem ever since we left CRM 4.0 behind. Continue reading “Show hierarchically related activities in subgrid”

Show ALL related activities in a subgrid

Microsoft Dynamics CRM offers great capabilities for activity entities, both out of the box and custom activities.
This post will describe a way to extend those capabilities even more, using a quite simple plugin.

During eXtremeCRM in Warsaw last week, a fellow CRMian and frequent user of FetchXML Builder approached me to ask if I knew a way to create “dynamic” queries with some contextual awareness. He had used unsupported methods to inject FetchXML to subgrids, to be able to show all activities related to current record, not just those where the record is related through the Regarding field. As I will show in this post, this can be accomplished with a simple plugin and a custom view.

Background

image
image
image

Activities handle e-mail, phonecalls, tasks, meetings, and even faxes and letters. Common custom activities are sms, transactions, and any other date-bound entity that involves participants of some kind. Participants can be contacts, accounts, leads, users, and the activities can be regarding eny entity with the “Activities” option selected. When looking at an associated view of a record to display associated activities, this can display activities where the current record is either recipient, sender, participant or regarding the activity. This is done with specialized views built into CRM, as this gives a useful overview of all activities concerning the party. The problem is when you want to have a similar view embedded on the form in a subgrid. In this case, you can only add activities related to the record through the Regarding lookup on the activities. This will of course only show a fraction of all activities that may be related to the contact, account, or any other entity form the subgrid is placed on.  

Solution – the customizations

image
image
image

To solve this, we need to modify the query that is executed by CRM. Instead of filtering activities based on the value in the Regarding field, we want to verify that the current record is any kind of “party” to the activity. First, create a custom view for the activities, with a signature that can be identified by our plugin so that it does not trigger when we don’t want it to. Open the “All Activities” view, and select Save As to create your custom view. Add a filter criteria to only show records where Activity does not contain data. Save the view. The view is now pretty unusable. It will never show any records as activity is required for the activitypointer pseudo entity.   Next, add a subgrid to the form where you want to show all activities, and select the new view as the default and only view. The customizations are now in place, and when we view any record with this form, nothing will show in the added subgrid.

Solution – the plugin

To get the query we want to be passed to CRM, we will intercept the RetrieveMultiple message in the execution pipeline before it goes to CRM. By analyzing the request we see that the query is formed like this, after conversion to FetchXML:

<fetch distinct='false' no-lock='true' mapping='logical' page='1' count='4' returntotalrecordcount='true' >
   <entity name='activitypointer' >
     <attribute name='subject' />
     ...
     <filter type='and' >
       <condition attribute='isregularactivity' operator='eq' value='1' />
       <condition attribute='activityid' operator='null' />
       <condition attribute='regardingobjectid' operator='eq' value='633929A2-F2E1-E511-8106-000D3A22EBB4' />
     </filter>
     <order attribute='scheduledend' descending='false' />
     <link-entity name='systemuser' to='owninguser' from='systemuserid' link-type='outer' alias='activitypointerowningusersystemusersystemuserid' >
       <attribute name='internalemailaddress' />
     </link-entity>
   </entity>
 </fetch> 

A bunch of included attributes have been excluded for readability
So, let’s create a plugin that triggers Pre RetrieveMultiple of activitypointer, and investigate if it has our “signature”.

      public void Execute(IServiceProvider serviceProvider)
         {
             ITracingService tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
             IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
             if (context.MessageName != "RetrieveMultiple" || context.Stage != 20 || context.Mode != 0 ||                 !context.InputParameters.Contains("Query") || !(context.InputParameters["Query"] is QueryExpression))
             {
                 tracer.Trace("Not expected context");
                 return;
             }
             if (ReplaceRegardingCondition(query, tracer))
             {
                 context.InputParameters["Query"] = query;
             }
         } 

This code is pretty self-explaining. The interesting part however, comes in the ReplaceRegardingCondition method…

        private static bool ReplaceRegardingCondition(QueryExpression query, ITracingService tracer)
        {
            if (query.EntityName != "activitypointer" || query.Criteria == null || query.Criteria.Conditions == null || query.Criteria.Conditions.Count < 2)
            {
                tracer.Trace("Not expected query");
                return false;
            }

            ConditionExpression nullCondition = null;
            ConditionExpression regardingCondition = null;

            tracer.Trace("Checking criteria for expected conditions");
            foreach (ConditionExpression cond in query.Criteria.Conditions)
            {
                if (cond.AttributeName == "activityid" &amp;&amp; cond.Operator == ConditionOperator.Null)
                {
                    tracer.Trace("Found triggering null condition");
                    nullCondition = cond;
                }
                else if (cond.AttributeName == "regardingobjectid" &amp;&amp; cond.Operator == ConditionOperator.Equal &amp;&amp; cond.Values.Count == 1 &amp;&amp; cond.Values[0] is Guid)
                {
                    tracer.Trace("Found condition for regardingobjectid");
                    regardingCondition = cond;
                }
                else
                {
                    tracer.Trace($"Disregarding condition for {cond.AttributeName}");
                }
            }
            if (nullCondition == null || regardingCondition == null)
            {
                tracer.Trace("Missing expected null condition or regardingobjectid condition");
                return false;
            }
            var regardingId = (Guid)regardingCondition.Values[0];
            tracer.Trace($"Found regarding id: {regardingId}");

            tracer.Trace("Removing triggering conditions");
            query.Criteria.Conditions.Remove(nullCondition);
            query.Criteria.Conditions.Remove(regardingCondition);

            tracer.Trace("Adding link-entity and condition for activity party");
            var leActivityparty = query.AddLink("activityparty", "activityid", "activityid");
            leActivityparty.LinkCriteria.AddCondition("partyid", ConditionOperator.Equal, regardingId);
            return true;
        }
image

A bit of explanation:
Line 3-7: First sanity check of the query to verify that we might find our signature.
Line 13-29: Looping through the conditions to find our signature.
Line 15-19: Identifies the null-condition that was introduced in the view.
Line 20-24: Identifies the relation for the view, used to extract the record id.
Line 30-34: Verification of our signature.
Line 35: Extract the id of the parent record which is being displayed.
Line 39: Remove the null-condition used only to identify our signature.
Line 40: Remove the condition that the activities must have current record as Regarding.
Line 43: Create link-entity to activityparty, where the current record should be found.
Line 44: Add condition that the associated party shall be the current record.
As can be seen in the Execute method above, if the query is updated by our code, the updated query will be put back into the plugin execution context, and thus the updated query is what will be executed by CRM.
Finally, the plugin shall be registered in CRM.

Result

image


The subgrid on the form now contains all activities that are related to the current contact, in this case.
If you activate Plug-in Trace Log for all executions, you can now see logs with something like this in the message block:

Checking criteria for expected conditions
Disregarding condition for isregularactivity
Found triggering null condition
Found condition for regardingobjectid
Found regarding id: 633929a2-f2e1-e511-8106-000d3a22ebb4
Removing triggering conditions
Adding link-entity and condition for activity party

Resources

The complete source code for this plugin, including a bit more extra debugging information than shown here, can be downloaded here.
A CRM solution with the customized activity view, modified contact form, the plugin assembly and a plugin step can be downloaded here as managed version and unmanaged version.

Integrating FetchXML Builder with other plugins

With the next release of FetchXML Builder for XrmToolBox it is possible for other tools to benefit from the UI FetchXML Builder offers to compose queries to be used for any purpose.

The MessageBus functionality introduced in pull request #101 of XrmToolBox makes it possible to communicate between plugins within the tool.
BDU-UseFXB1This is implemented in the Bulk Data Updater (currently available as beta in Cinteros’ set of tools for XrmToolBox at http://cinteros.xrmtoolbox.com) to be able to use FetchXML Builder to get the query to use when retrieving records to update.
Using the MessageBus, it is really easy to get FXB to do the work for you when you need a FetchXML string or a QueryExpression object in your plugin. When communicating with FXB, the argument passed between the plugins shall be an instance of FXBMessageBusArgument, which is a public class in the FXB assembly.  

Preparation

To prepare your plugins for integration, implement the IMessageBusHost interface in both source and target plugins.

    public partial class DataUpdater : PluginBase, IGitHubPlugin, IPayPalPlugin, IMessageBusHost

Sample call to start FXB

Clickin the button in the above image will execute the following code:

  var messageBusEventArgs = new MessageBusEventArgs("FetchXML Builder");
  messageBusEventArgs.TargetArgument = new FXBMessageBusArgument(FXBMessageBusRequest.FetchXML)
  {
    FetchXML = internalFetchXml
  };
  OnOutgoingMessage(this, messageBusEventArgs);

This will start FetchXML Builder with a new button in the toolbar – “Return FetchXML”. FXB will be initiated with the current FetchXML stored in the internalFetchXml variable in Bulk Data Updater.
BDU-UseFXB2

Sample method to receive query from FXB

When the return-button is clicked in FetchXML Builder, a similar MessageBus event is triggered in the calling plugin.

public void OnIncomingMessage(MessageBusEventArgs message)
{
    if (message.SourcePlugin == "FetchXML Builder" &&
        message.TargetArgument is FXBMessageBusArgument)
    {
        var fxbArg = (FXBMessageBusArgument)message.TargetArgument;
        internalFetchXml = fxbArg.FetchXML;
    }
}

The MessageBuEventArgs in this event now contains a TargetArgument of type FXBMessageBusArgument. Depending on the request that was made to FetchXML Builder, the argument till contain a FetchXML string or a QueryExpression object.
 

Timeline

When writing this blog, a public release of XrmToolBox and FetchXML Builder including MessageBus functionality is not yet available. Tanguy Touzard, author of XrmToolBox, plans to have this release available for the public “early May”. FetchXML Builder supporting this functionality will be available at the same time, or shortly after.
However:

This means that plugins with the need to use FXB to compose their queries can also be implemented now, to be able to release the plugins when the MessageBus framework is released to public. The easiest way to get the FXB interface is to download the draft release available at GitHub and reference the FXB assembly in your plugin.
 

Background

  • XrmToolBox is the toolkit to use to survive the everyday challenges for Microsoft Dynamics CRM administrators, customizers and developers. XrmToolBox can be downloaded from http://www.xrmtoolbox.com
  • FetchXML Builder is one of about 40 publicly available tools for XrmToolBox. FetxhXML Builder can be downloaded from http://fxb.xrmtoolbox.com
  • Bulk Data Updater is one of the tools for XrmToolBox from Cinteros AB currently in beta release. Cinteros toolkit can be downloaded from http://cinteros.xrmtoolbox.com

Note – if you would like to see an OData query string returned from FetchXML Builder, make sure you vote up issue #4 on GitHub!