Debugging custom workflow assemblies

Plugin Registration tool can be used to debug not just plugin assemblies, but also custom workflow assemblies. I am not sure how well known this feature is, as I could not find any documentation about this in msdn.

Prerequisite

Use the correct version of Plugin Registration tool for your organisation. I could not use Plugin Registration tool that came along with CRM SDK 7.1.1, to debug a workflow assembly running in CRM 2015 Update 0.1 (7.0.1). I could however use Plugin Registration tool 8.0.0.7198 to debug workflow assembly running in CRMOnline 2016 (8.0.1.79). So, it seems the major version and minor version have to match to enable workflow assembly debugging.

After installing the profile, select the plugin profile node. You will now see a new button called “Profile Workflow

Workflow Profile Button

Next, choose the CRM workflow which contains the custom workflow assembly. If the workflow has multiple custom workflow assembly steps, you will see each of these in this screen. You can choose the assembly to profile. It is best to choose “Persist to Entity” option, as you won’t see the exception when it is thrown by the workflow.Profile Settings

 

Once you click OK, a clone of the workflow will be created. It will have “(Profiled)” in the end. Your original workflow will now be in “Draft” state.

Workflow Cloned

Now execute the profiled workflow manually. Confirm that the workflow has finished running.

Workflow Log

Once the workflow has completed running, you can now use the serialised profile to debug the workflow assembly. After you click the “Replay Plugin Execution” button you will see this screen, which will help you to select the correct profile record.

Debug Profile Selection

I ran the workflow manually only once and hence there is only one profile row. If the workflow ran multiple times, you will see multiple rows. After you click select, you’ll then have to choose the correct workflow assembly that matches this profile.

Start Debug

Now attach the Visual Studio Debugger to the Plugin Registration Tool. Now is also a good time to put couple of breakpoints in the workflow assembly code in Visual Studio. Once you click “Start Execution”, the control should now be transferred to Visual Studio to facilitate debugging.

Visual Studio Debug

The behaviour is exactly same as plugin debugging. You can step though the code, understand the root cause of any weird behaviour and resolve it. Once you complete the execution, you will see the trace logs in the profiler.

Debug Result

One more thing: You can use this exact same process to debug an Action which has a custom assembly. Here is how the profile looks when an action with custom workflow assembly is profiled.

Debug an action

Things to note:

  1. When a workflow step is profiled, the workflow assembly containing this activity is cloned and registered as a profiled workflow assembly. It is this assembly that is used in the workflow that has the name ending with “(Profiled)”
  2. Even though you can see the workflow being profiled, stopping the workflow profile using the Plugin Registration tool seems impossible. You can see what is being profiled.Profiled Workflow
  3. In order to stop profiling, you’ll have to
    • Unpublish and delete the workflow/action that ends with “(Profiled)
    • Delete the weirdly named assembly (all guid name) from the “Default Solution“. This will be under the “Plugin Assemblies” nodeCloned Workflow Assembly

I hope this technique will help you to debug custom workflow assemblies quite easily. Happy debugging.

EDIT (01/07/2016): Please refer Issues in debugging custom workflow assemblies where I address the issues in the comment.

Quicktip: Debugging merged plugin assembly

Plugin profiling and debugging is a very useful feature in the plugin registration tool. It helps you to debug and step through the plugin code in your local machine with Visual Studio, using the serialised plugin context. The serialised context can also be stored in CRM and debug can be initiated from this record.

Profile Screen

There is one small issue when you try to debug a IL Merged assembly. When you try to profile such a plugin assembly, you will get an error like this.

PluginRegTool Error

The error is saying that the plugin profiler cannot locate the assembly that was merged with the main plugin assembly.

Resolution:

Copy all the assemblies that were merged with the plugin assembly that you are trying to debug, into the same directory as the Plugin Registration tool executable.

I experienced this issue when I was trying to debug a plugin assembly merged using the CRM Solution Manager.

Further reading:

Debug a plugin – https://msdn.microsoft.com/en-us/library/gg328574.aspx

Bookmarklet: Turn off autosave & lookup on newwindow

The first bookmarklet turns off autosave for the current record, and refreshes the form without saving. Drag the below to your favorites bar.

javascript:(function(){var%20contentPanels=Array.from(document.querySelectorAll('iframe')).filter(function(d){return%20d.style.visibility!=='hidden'});if(contentPanels&&contentPanels.length>0){var%20Xrm=contentPanels[0].contentWindow.Xrm;Xrm.Page.data.refresh(false).then(function(){Xrm.Page.data.entity.addOnSave(function(econtext){var%20eventArgs=econtext.getEventArgs();if(eventArgs.getSaveMode()===70||eventArgs.getSaveMode()===2){eventArgs.preventDefault();}});alert('Form%20refreshed%20without%20save.%20Autosave%20turned%20off.');},function(errorCode,message){alert(message);});}else{alert('Entity%20form%20not%20detected');}})();void%200;

Below the unminified source.

(function () {
	var contentPanels = Array.from(document.querySelectorAll('iframe')).filter(function (d) {
			return d.style.visibility !== 'hidden'
		});
	if (contentPanels && contentPanels.length > 0) {
		var Xrm = contentPanels[0].contentWindow.Xrm;
		Xrm.Page.data.refresh(false).then(function () {
			Xrm.Page.data.entity.addOnSave(function (econtext) {
				var eventArgs = econtext.getEventArgs();
				if (eventArgs.getSaveMode() === 70 || eventArgs.getSaveMode() === 2) {
					eventArgs.preventDefault();
				}
			});
			alert('Form refreshed without save. Autosave turned off.');
		}, function (errorCode, message) {
			alert(message);
		});
	} else {
		alert('Entity form not detected');
	}
})();

The second bookmarklet open the selected lookup in a new window. Starting from CRM2015 every link you click inside a record form, opens in the same window. This can be annoying sometimes. To use this bookmarklet, you’ll just have to select the lookup on the record and execute the bookmarklet. This will open the lookup record in a new window. Below is the bookmarklet.

javascript:(function(){var%20contentPanels=Array.from(document.querySelectorAll('iframe')).filter(function(d){return%20d.style.visibility!=='hidden'});if(contentPanels&&contentPanels.length>0){var%20Xrm=contentPanels[0].contentWindow.Xrm;var%20currentControl=Xrm.Page.ui.getCurrentControl();if(currentControl.getControlType()==='lookup'){var%20currentLookup=currentControl.getAttribute().getValue();if(currentLookup){var%20entityName=currentLookup[0].type,entityId=currentLookup[0].id;var%20url=Xrm.Page.context.getClientUrl()+'/main.aspx?etc='+entityName+'&id='+entityId+'&newWindow=true&pagetype=entityrecord';window.open(url,'_blank');}}else{alert('The%20currently%20selected%20control%20is%20not%20a%20lookup');}}else{alert('Entity%20form%20not%20detected');}})();void%200;

This is the unminified source.

(function () {
	var contentPanels = Array.from(document.querySelectorAll('iframe')).filter(function (d) {
			return d.style.visibility !== 'hidden'
		});
	if (contentPanels && contentPanels.length > 0) {
		var Xrm = contentPanels[0].contentWindow.Xrm;
		var currentControl = Xrm.Page.ui.getCurrentControl();
		if (currentControl.getControlType() === 'lookup') {
			var currentLookup = currentControl.getAttribute().getValue();
			if (currentLookup) {
				var entityName = currentLookup[0].type,
				entityId = currentLookup[0].id;
				var url = Xrm.Page.context.getClientUrl() + '/main.aspx?etc=' + entityName + '&id=' + entityId + '&newWindow=true&pagetype=entityrecord';
				window.open(url, '_blank');
			}
		} else {
			alert('The currently selected control is not a lookup');
		}
	} else {
		alert('Entity form not detected');
	}
})();

References:

https://msdn.microsoft.com/en-us/library/gg509060.aspx

Improving CRM grids with TableTools2

It is no secret that I am a big fan of the free/opensource tools that fit in nicely with Dynamics CRM. I am also a big fan of bookmarklets that improve your productivity around common repetitive tasks. Firefox is my primary browser for Dynamics CRM, and Chrome is my primary browser when it comes to Javascript debugging. I use Internet Explorer only when a CRM bug prevents me from using either or these, or an user report a issue that it IE specific.

If you don’t use Firefox, this post won’t be of much help to as this addon is Firefox only. The addon I am talking about is tabletools2. This extension is not open source, but is free to use. It would definitely be nice to look at the source, but it is free and super awesome, so I will ignore this point for now.

How this extension improves productivity

IMHO, CRM2016 lacks UX consistency in some areas. One of these is grid. You would not universally see the filter button on the right side, when a grid is displayed. In some pages, you would see it, in some pages you won’t. You can use the addon in grids that don’t display a filter or just in general with any page that displays a table like structure.

With Filter – Plugin Assemblies from Solution

WithFilter.png

Without Filter – Clicking a node inside the plugin assemblies

WithoutFilter.png

Without Filter – Bulk Record Deletion

WithoutFilter2

Without Filter – Add multiple users from Security area (popup)

WithoutFilter3

This one is a popup and so in this scenario, the behavior is consistent with the lookup popup window.

Now lets look how tabletools2 can improve the Bulk Record Deletion grid. Hover over the grid and do this: Ctrl – Shift – Left Click and then Ctrl – Shift – Right Click. This is how the page looks after you do this.

BulkDeleteWithFilter

Yellow text box on each column search and filter the current rows immediately. Turquoise text boxes display the list of unique values on each column and you can filter by this value (like Excel).

I tried this on the attribute screen, which doesn’t have OOB filter button either.

AttributeWithFilter

When the CRM grid lacks filter I usually follow one or both these approaches.

  1. Use browser search with Ctrl-F and highlight the matches
  2. Sort by a particular column

The extension is really useful in the regard, as it can add this functionality locally on the client side on-demand. One thing to note is the search and filter is restricted to the rows on the current page only. It doesn’t search across all pages. There is also heap on other functionalities with the extension, but this is what I currently use. Watch the video below for a quick overview.

Edit in Excel Online from Advanced Find

Editing in Excel Online, is a CRMOnline only feature (surprise surprise) that was rolled out with CRMOnline 2015 Update 1. Currently there is one limitation that I find quite annoying: You cannot open an Advanced Find result in ExcelOnline. This ribbon button pops up only with saved views. In this post, I will detail on how you can get around this.

  1. Create a new solution with just the entity/entities you need this capability for. This is so that the solution will load quickly with Ribbon Workbench. If your organisation has already been updated to CRM2016, just click OK after clicking the “Add Existing” button under the Entity node. In this screenshot below, I am going to edit the contact ribbon. Notice that only “Include entity metadata” is selected
    SolutionScreen
  2. Install Ribbon Workbench (here after referred as RWB)
  3. Open the CRM solution you created from RWB
  4. The command you have to modify is Mscrm.ExportToExcel.Online. I found this part a little fiddly. You have to left click a couple of times across all the Excel menu options and then right click and choose “Customise command” once you have visually confirmed that you have chosen the correct command. It is the first one on the Export menu.
    ExcelMenuExcelOnlineButtonCommand

    Commands

  5. Right click on the command, choose visibility rules and move the Mscrm.NotAdvancedFind rule to the left hand side i.e. deselect this rule for the Mscrm.ExportToExcel.Online command
    Edit Display RuleVisibilityRules
  6. For these Display Rules set IsCore to true: Mscrm.IsExportToExcelOnlineEnabled, Mscrm.HideIfExportToExcelNotEnabled, Mscrm.HideOnPhone
    IsCoreSetting
  7. Save/Publish the changes from RWB

After you do this the “Export in Excel Online” menu will be available in the Advanced Find.

Advanced Find menu

These are the limitations/issues:

  1. You have to save your Advanced Find query as a Personal view. You cannot use adhoc Advanced Find query, and edit the results in Excel Online. This may or may not be a deal-breaker depending on your situation. I find this OK at the moment.
  2. After you work with your data in Excel Online and click “Return to CRM List” the Advanced Find ribbon is gone. Fix for this is to just refresh the Advanced Find window.
    Ribbonless Advanced Find

I am not sure if Microsoft has hidden this capability from Advanced Find on purpose while they work on the issues, or whether this is going to be a saved view only feature. But till Microsoft exposes this properly from Advanced Find, you can use this approach as a stop-gap measure.

Thank you @scottdurow for suggesting the IsCore=true fix.

Further reading:

  1. https://www.microsoft.com/en-us/dynamics/crm-customer-center/analyze-your-crm-data-in-excel-online.aspx
  2. https://ribbonworkbench.uservoice.com/