Case closed: Managed or Unmanaged solutions in Microsoft Dynamics 365 / CRM

If you have problems shifting gears in your car, you don’t call Volvo to say “Hey, I don’t like how this gear shifting thing works, so I’m just going to use reverse and drive backwards from now on.”
What you probably do is call them to say “I’m having trouble shifting, you need to fix the problems or show me how to use it properly.


Ever since Microsoft introduced the Solution platform with Dynamics CRM 2011, there has been an ongoing and never ending discussion about whether to deploy managed or unmanaged solutions.

I can’t say I can end the discussions or solve all problems. But I will try to convince you – there is no discussion.

Continue reading “Case closed: Managed or Unmanaged solutions in Microsoft Dynamics 365 / CRM”

Public Preview: Build and Deploy Microsoft Dynamics 365 projects using VSTS

Recently I posted a series of three articles describing our approach to DevOps for Microsoft Dynamics 365, and the technology behind it.
After giving a session on this topic at CRM Saturday in Madrid, Spain, it is now time to announce “public preview” of our tools.

If you want the full story – these are the articles describing the background and technology behind our tools:

Part I – Background and how our DevOps tools evolved before we knew about it
Part II – Automation of the build and deploy process using custom VSTS Build Tasks
Part III – Demo of complete build and release definitions taking you from A to Z

Continue reading “Public Preview: Build and Deploy Microsoft Dynamics 365 projects using VSTS”

Build and Deploy Microsoft Dynamics 365 projects using VSTS – part III

This is the third and last article telling the tale of our own DevOps for Microsoft Dynamics 365, and the technology behind it.

Part I – Background and how our DevOps tools evolved before we knew about it
Part II – Automation of the build and deploy process using custom VSTS Build Tasks
Part III – Demo of complete build and release definitions taking you from A to Z
After the first two articles we have now got a handful custom VSTS Build Tasks to help us take the build and deployment automation all the way. This final article demonstrates how we do that with VSTS builds and releases. Finally raising the questions of why we did all this and where to go from here.

A complete VSTS Build for Microsoft Dynamics 365

image_thumb113Below is a sample of a full build process that not only builds and packs a new CRM solution, but updates the individual assemblies and webresources in DEV environment, exports solutions and data, and then publishes the files exported from DEV together with Shuffle Definitions and Package Definition, which is the resulting build artifact.

Continue reading “Build and Deploy Microsoft Dynamics 365 projects using VSTS – part III”

Build and Deploy Microsoft Dynamics 365 projects using VSTS – part II

This is the second article of three telling the tale of our own DevOps for Microsoft Dynamics 365, and the technology behind it.

Part I – Background and how our DevOps tools evolved before we knew about it
Part II – Automation of the build and deploy process using custom VSTS Build Tasks
Part III – Demo of complete build and release definitions taking you from A to Z In the previous article I described the background of our struggles with moving configuration data and later scripted export and import of solutions and the CRM Deployer tool. This article takes these features to the next level by packing those and some other missing features into custom VSTS Build Tasks.

Automating the Build Process

We now had the tools we needed to automate the central parts of the build/deploy process. But it still involved lots of manual or script based steps. To describe it simply, the following steps were required to produce a full deploy of a Customer Solution (CS) that has a prerequisite in one of our Product Solutions (PS), assuming we wanted the latest available code and customizations for both PS and CS.

  1. Build PS
    1. Define new PS version number
    2. Set version number for assemblies
    3. Compile assemblies
    4. Use Plugin Registration to update PS DEV assemblies
    5. Minify webresources (scripted post build event)
    6. Use Web Resource Utility to update webresources in PS DEV
      (scripted post build event using modified version from SDK, that allows command line execution w/o user interaction)
    7. Run Shuffle scripts that export PS solutions and data from PS DEV
  2. Build CS
    1. Run scripts that import PS to CS DEV
    2. Define new CS version number
    3. Set version number for assemblies
    4. Compile assemblies
    5. Use Plugin Registration to update CS DEV assemblies
    6. Minify webresources
    7. Use Web Resource Utility to update webresources in CS DEV
    8. Run Shuffle scripts that export CS solutions and data from CS DEV
  3. Create package (by running a script)
    1. Collect all required definitions, solutions and data files from PS and CS exports
    2. Execute CRM Deployer with cdpkg file and a flag to create cdzip archive

The missing pieces

Some of the steps above would be possible to encapsulate a bit more with scripting or tailored tools, and some of them possible to perform using Microsoft’s Developer Toolkit, Jason Lattimer’s CRM Developer Extensions or Wael Hamze’s CI FrameWork. But with the legacy of our Shuffle and later the CRM Deployer, that both have well proven technology and still save us literally hundreds of hours every month, we decided to add the few missing pieces in our puzzle ourselves. Continue reading “Build and Deploy Microsoft Dynamics 365 projects using VSTS – part II”

Build and Deploy Microsoft Dynamics 365 projects using VSTS – part I

During my eight years as a Microsoft Dynamics CRM / 365 developer, I have felt a strong pain every time it was time to package and distribute a customer or product implementation.

Over the years our tools have evolved to now support a complete automated process; from source repository via compilation, updating dev environment, exporting solutions and configuration, collecting the artifacts and compose deployment packages to be installed manually or by VSTS release management.

This is the first article of three telling the tale of our own DevOps for Microsoft Dynamics 365, and the technology behind it.

Part I – Background and how our DevOps tools evolved before we knew about it
Part II – Automation of the build and deploy process using custom VSTS Build Tasks
Part III – Demo of complete build and release definitions taking you from A to Z   My hope is that these articles will inspire you to take your delivery process to the next stage by implementing automation through CI and what is usually called DevOps. If you are already there, these articles should provide an alternative solution, which may or may not suit your needs today, but might be worth considering.

It started with the data

Back in the days of CRM 4.0 we started delivering systems that were based more and more on generic configurable functionality. The benefit of having an automated way of delivering and moving configuration data between CRM environments was becoming increasingly obvious. This was long before utilities like the Configuration Migration Tool, so we started to draw the blueprints to develop the functionality we needed. Basically, what we needed was to grab a bunch of data from a source environment to persist it in a file, and later push it into another CRM organization.

Continue reading “Build and Deploy Microsoft Dynamics 365 projects using VSTS – part I”

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.

Solution Segmentation for entity ribbons

The new feature for segmenting solutions in Microsoft Dynamics CRM is absolutely awesome.
It finally allows you to only include the parts you actually want your solution to change.

For us as an ISV this is a huge improvement. We can now deliver solutions that are completely “plug and play” and still leave a minimal footprint on the whole customer system.

RibbonDiffXml segmentation

There is however one thing that is still not possible to separate with enough granularity. To include the ribbon definition of an entity, you need to check the Include entity metadata checkbox. image Unfortunately this also includes the entity display name, plural name, and all other “entity wide” settings such as Notes, Connections, Mail merge etc. The result of this is that if we include the Contact entity just to be able to add a solution specific button to the command bar, we must also include the entity settings.

Problem

When a customer has developed their own solutions, or got solutions from other third parties, we quite often face the situation where they have changed the name of an entity, e.g. Contact is renamed to Person. Now importing our solution to add this button to the contact command bar, will also change the name of the contact entity back to default, or rather to whatever it is called in our solution.

Solution

This could be solved by allowing a separate option for the RibbonDiff part of the entity definition when selecting components for the solution.

Vote!

If you agree with this proposal, you can contribute by voting up this item on Microsoft Connect.

Read more

MVP Jukka Niiranen recently wrote an excellent article describing Solution Segmentation in Microsoft Dynamics CRM.