Introducing VSTS Quick Reply: a Chrome extension that helps you collaborate quicker in VSTS discussion

Teams often leverage the discussion feature, in particular the ability to @mention team members, in VSTS for work items to collaborate on requirements, tasks and bugs. In large teams it is common to @mention several team members on messages to ensure that the relevant people are involved in the discussion.

VSTS however currently does not have a “Reply all” feature, which means you have to manually @mention each member in the previous message when replying to a discussion post.

I have developed a simple Chrome extension, VSTS Quick Reply, to help with this. This simple extension adds a Reply and Reply All links to each discussion message that have been posted against the current work item. When clicked, these links add all the @mentioned users and/or the original poster of the selected message to your new message entry textbox so that you don’t have to manually type them again.

Currently this extension only supports VSTS. You can install this extension from the Chrome Web Store.

That’s it! I hope this simple extension can give you a small productivity boost when collaborating in VSTS. I would love to hear from you with feedback and suggestions!

Posted in TFS, VSTS | 5 Comments

How to get current user info in VSTS web by JavaScript

I have been exploring extending the VSTS web interface and I needed to get the display name of the current user in JavaScript. It turns out there is a JavaScript variable that is available on all pages, namely __vssPageContext. This variable contains many contextual information. I was able to get what I needed from __vssPageContext.webContext.user:

Posted in TFS, VSTS | Leave a comment

Getting VSTS user ID by display name using REST

I have been exploring the VSTS REST API lately. While there are quite a few services that require the user ID as parameter, it isn’t very obvious how you can obtain that user ID for a given user in the first place.

For my requirement I needed to get the user ID for a given user by their display name. The only way I have found to achieve this (via REST) is to use the Graph service, which is still in preview. The steps are described below.

First, we need to call the List all users service (https://[account] This will return a list of all users. Each user record has the following structure:

	"subjectKind": "user",
	"domain": "Windows Live ID",
	"principalName": "[value removed]",
	"mailAddress": "[value removed]",
	"origin": "msa",
	"originId": "[value removed]",
	"displayName": "[value removed]",
	"_links": {
		"self": { "href": "https://[account][value removed]" },
		"memberships": { "href": "https://[account][value removed]" },
		"membershipState": { "href": "https://[account][value removed]" },
		"storageKey": { "href": "https://[account][value removed]" },
		"avatar": { "href": "https://[account][value removed]" }
	"url": "https://[account][value removed]",
	"descriptor": "msa...[value removed]"

Using the displayName property we can locate the user record that we are after. We then need to invoke the service identified by the _links.storageKey property to retrieve the ID for this user. The URL of this service looks like this (value has been changed):


The above service returns a structure as follow:

	"value": "[GUID]",
	"_links": {
		"self": { "href": "https://[account][value removed]" },
		"descriptor": { "href": "https://[account][GUID]" 

The ID of the user can be found in the value property.

So there you have it…

Unfortunately currently it requires two calls to get the ID of a user given their display name. This might change in the future though as Microsoft’s documentation is indicating that the ability to search for user by UPN or display name is coming soon to the Graph service.

Posted in TFS, VSTS | Leave a comment

How to edit related entity in CRM Portal web form step

In CRM Portal, different web form steps of a web form can operate on different entities. Imagine you have an Enrolment web form that allows students to enrol in courses. The first step of this form might capture student details (Student entity). The second step might capture the enrolment details (Course Enrolment entity). The Student entity would have a lookup to the Course Enrolment entity in this particular example.

Each web form step of the web form must have a Mode specified, which can be Insert, Edit or ReadOnly. If you want to allow users to be able to edit the form (e.g. save and resume), then you would typically need (at a minimum) a web form where all the steps are set to Edit mode.

As the 2nd step operates on a related record, and not the main record that the user clicked on to launch the form however, there is no OOTB way to configure this as an Edit step.

This is because for Edit mode, we need to provide the step with the source record. OOTB however, the available options are:

  1. Query String
  2. Current Portal User
  3. Result From Previous Step
  4. Record Associated to Current Portal User

Since our record is not related to the current Portal User, option 2 and 4 above are no good. Since the record that our 2nd step operates on is different to that of the 1st step, option 3 is also no good. The only viable option for us is the first option, Query String.

The problem here is that CRM Portal does not include the ID of the related record (the one our 2nd step operates on) in the URL when the user navigates to the 2nd step of the form.

So how do we workaround this?

The workaround…

The workaround, at a high level, is to use JavaScript to manipulate the URL to pass the ID of the related record in the query string to our 2nd step. This JavaScript will run on load of the 1st step, and update the action property of the form HTML element. This effectively changes the URL that is used to navigate to the 2nd step.

Perform the following:

  • Add the lookup field to the related entity (e.g. new_courseenrolmentid) to the backing CRM form of the 1st step. This enables our JavaScript on the web form step to read this value.
  • Make the lookup field above read-only on the backing CRM form so that users cannot update this field on the Portal.
  • Configure the following JavaScript for the 1st web form step. This script passes the ID of the related record to the 2nd web form step using the ‘relatedid‘ query string parameter. Please review the in line comment.
function appendRelatedEntityIdToQueryString() {
	//Append the ID of the related record to the form's post URL using the 'relatedid' query string parameter.
	//If this query string param already exists in the URL then it is updated. Else, it is appended to the end of the URL.

	var relatedEntityId = $("#new_courseenrolmentid").val();

	var $form = $("form");
	var formActionUrl = $form.prop("action");

	if (formActionUrl.indexOf("&relatedid=") == -1) {
		//The URL does not contain our param so just add it.
		formActionUrl += "&relatedid=" + relatedEntityId;
		$form.prop("action", formActionUrl);

	//Find the existing param in the URL and replace its value.
	var queryStringStartIndex = formActionUrl.indexOf("?") + 1;
	var queryString = queryStringStartIndex == 0 || queryStringStartIndex == formActionUrl.length
		? ""
		: formActionUrl.substring(queryStringStartIndex);

	var queryPairs = queryString.split("&");

	var newQueryString = "";

	for (var i = 0; i < queryPairs.length; i++) {
		/*Find the relatedid and replace it.*/

		if (queryPairs[i].indexOf("relatedid=") == 0) {
			queryPairs[i] = "relatedid=" + relatedEntityId;

		if (newQueryString == "") {
			newQueryString = queryPairs[i];
		} else {
			newQueryString += "&" + queryPairs[i];

	formActionUrl = formActionUrl.substring(0, queryStringStartIndex) + newQueryString;
	$form.prop("action", formActionUrl);

$(function () {
  • Configure the 2nd web form step as follow:
    • Set Target Entity Logical Name to the related entity (e.g. Course Enrolment)
    • Set Mode to Edit
    • For Record Source:
      • Set Source Type to Query String
      • Set Primary Key Query String Parameter Name to relatedid
      • Set Primary Key Attribute Logical Name to the lookup field (e.g. new_courseenrolmentid) on the primary entity

That’s it!

Now you should be able to edit the related entity on your 2nd web form step.

By the way…

Do a lot of JavaScript, CSS, HTML and Liquid coding with CRM Portal? Want to source-control these artefacts and work together with your team without overwriting each other’s code? Then check out my Visual Studio extension CRMQuickDeploy! This simple extension allows you to work with these artefacts in Visual Studio and quickly deploy them to CRM!

Posted in CRM, CRM Portal | Leave a comment

Loading entity form dynamically from JavaScript in CRM Portal

This has been tested on xRM Portal CE only.

There may be times where you need to load and display an entity form by JavaScript in CRM Portal. For example, you may have a content page with a link that when clicked, should display an entity form in a modal dialog. You want the modal dialog to display the entity form without any of the site’s branding, navigation, footer, etc.

You can achieve this by leveraging an OOTB service that renders the entity form. This is the same service that is used by the OOTB entity lists and sub-grids.

The service…

The URL for this service is:


  • portalId: The service seems to be happy with any GUID. We used an empty GUID (00000000-0000-0000-0000-000000000000) and it was fine.
  • recordId: Guid of the record you want to display
  • entityFormId: Guid of the entity form record you want to use

This service returns an HTML document containing the specified entity form loaded with the specified record. The site’s branding, navigation, footer, etc. are excluded, which means the HTML document is ready to be used in a modal dialog via an iframe.

The modal dialog…

CRM Portal uses Bootstrap, so we will use Bootstrap’s modal to load an iframe that invokes the service above and displays the entity form. Again, this is the same approach used by the OOTB entity lists and sub-grids.

Below is the HTML that should be added to the page. The first part (the div) is the normal page content. The second part (the section) is the modal dialog that stays hidden until the user clicks the link in our content. The code for this second part was adapted from the modal element used by the OOTB entity list. Please review the inline comments below.

<!--This is our main content-->

	Hello world. <a href="javascript:loadEntityFormAsModal();">Click me!</a>

<!--Code adapted from modal element of entity list. The ID of the section element is used in the JavaScript below.-->

<section id="myModalDialog" aria-hidden="true" aria-label="<span class='fa fa-info-circle' aria-hidden='true'></span> My Modal Title" class="modal fade modal-form modal-form-details" data-backdrop="static" role="dialog" tabindex="-1" style="display: none;">
	<div class="modal-lg modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<button aria-label="Close" class="close" data-dismiss="modal" tabindex="0" title="Close" type="button">
					<span aria-hidden="true">×</span><span class="sr-only">Close</span>
				<h1 class="modal-title h4" title="My Modal Title">My Modal Title</h1>
			<div class="modal-body">
				<div class="form-loading" style="display: none;">
					<span class="fa fa-spinner fa-spin fa-4x" aria-hidden="true"></span>

				<iframe src=""></iframe>

Next we need to add the below JavaScript to the page. If embedded on the same page, then should be wrapped in <script> tags. This script was adapted from the OOTB entity-grid.js script. Please review the inline comments below.

function loadEntityFormAsModal() {
	//Code adapted from entityGrid.prototype.addDetailsActionLinkClickEventHandlers in \js\entity-grid.js.

	//Setup the record and entity form you want to display
	var portalId = "00000000-0000-0000-0000-000000000000";
	var recordId = "B3FEC1EB-7F68-E811-859D-B86B23AC9F7C";
	var entityFormId = "396293DD-9D46-E811-8551-B86B23AC9F7C";

	//Form the URL to the service
	var url = "/_portal/modal-form-template-path/" + portalId + "?id=" + recordId + "&entityformid=" + entityFormId;

	//This ID needs to match the ID of the modal section element.
	var $modal = $("#myModalDialog");

	//Retrieve the iframe of the modal and set it load the service
	var $iFrame = $modal.find("iframe");

	$iFrame.attr("src", url);

	//Hook in handler to hide loader image when done loading
	$iFrame.on("load", function () {

	//Show the loader image at start

	$modal.on('', function () {
		$modal.attr("aria-hidden", "false");

	$"").on("", function () {
		$modal.attr("aria-hidden", "true");


That’s it!

And there you have it, you can now dynamically launch an entity form in JavaScript. Leveraging the OOTB service means that any entity permissions you may have setup will be honoured, and any JavaScript attached to the entity form itself will also be executed.

By the way…

Do a lot of HTLM, JavaScript, CSS and Liquid coding in CRM Portal? You should check out my Visual Studio extension CRMQuickDeploy. This allows you to work with HTML, JavaScript, CSS and Liquid in Visual Studio and quickly deploy them to CRM Portal. Not only this improves your productivity, but also allows you to source control these artefacts and facilitates scenarios where multiple developers work on the same code base.

Posted in CRM, CRM Portal | 6 Comments

Get current entity logical name and record ID in CRM Portal forms using JavaScript

Use the following JavaScript to retrieve the current entity logical name and record ID in CRM Portal forms:

For Entity Form:

Entity logical name: $(“#EntityFormControl_EntityFormView_EntityName”).val()

Record ID: $(“#EntityFormControl_EntityFormView_EntityID”).val()

For Web Form Step:

Entity logical name: $(“#EntityFormView_EntityName”).val()

Record ID: $(“#EntityFormView_EntityID”).val()

Tested on xRM Portal CE.


UPDATE 10/01/2019:

The HTML structure is now different for Portal version (cloud). There is now a GUID in the HTML field ID, e.g. EntityFormControl_978076ec8cf7e811a965000d3ae13a46_EntityFormView_EntityID.

For Entity Form, use the following:

  • Entity logical name: $(“input[id^=’EntityFormControl_’][id$=’_EntityFormView_EntityName’]”).val()
  • Record ID: $(“input[id^=’EntityFormControl_’][id$=’_EntityFormView_EntityID’]”).val()
  • Record state: $(“input[id^=’EntityFormControl_’][id$=’_EntityFormView_EntityState’]”).val()
  • Record status: $(“input[id^=’EntityFormControl_’][id$=’_EntityFormView_EntityStatus’]”).val()
Posted in CRM, CRM Portal | Leave a comment

Leveraging built-in services in CRM Portal

On a recent project we decided to build a custom entity list using jQuery DataTables as the OOTB entity list did not meet our requirements. As part of this we needed to build a delete list item functionality that should work similarly to the OOTB counterpart. To achieve this we needed a service that we can call from JavaScript to delete a given record (i.e. a list item).

After some investigation, we discovered that there are several built-in services in CRM Portal that we can invoke using JavaScript. These are the same services used by the OOTB components. Using these services means that we did not have to develop/deploy a custom service to support our custom UI component. It also means that the entity permissions we have configured in CRM are automatically honoured, which is a huge bonus.

In this post I will write about these built-in services, in particular the ‘delete list item’ service, and how you can call them from your JavaScript.

Important: this investigation was done against xRM Portals Community Edition (i.e. the on-prem version of CRM Portal). The findings may or may not apply to CRM Portal on cloud that is hosted by Microsoft. References to source code refer to the source code of XRM Portals Community Edition, which can be downloaded from

The built-in ‘delete list item’ service

This service lives at [portalUrl]/_services/entity-grid-delete/[recordId to delete]. You can invoke this service by performing a POST to this URL. The service accepts an EntityReference parameter to identify the record to delete, and it expects to find this in the POST’s body as JSON, e.g.:


This particular service route maps to the Delete method of the class Site.Areas.Portal.Controllers.EntityGridController, which is defined in the file \Areas\Portal\Controllers\EntityGridController.cs of the Portal project.

A side note: other built-in services

The route mapping of the ‘delete list item’ service is defined in the RegisterArea method of the Site.Areas.Portal.PortalAreaRegistration class, which is defined in the file \Areas\Portal\PortalAreaRegistration.cs of the Portal project.

Reviewing this file quickly shows that there are actually many more built-in services in CRM Portal that you should be able to invoke from JavaScript. Below is a screenshot to illustrate:

Invoking the ‘delete list item’ service from JavaScript

There is a slight complication in invoking this service from JS, and that is it has anti-forgery enabled. This means that our requests to the service must contain a __RequestVerificationToken header with a valid token value.

Fortunately CRM Portal has a built-in JavaScript object that helps us with this. Every page in the Portal automatically includes a reference to the JS file \js\antiforgerytoken.js. This JS defines a global object called shell, which has a method called ajaxSafePost.

ajaxSafePost is essentially a wrapper around jQuery’s ajax method, and is responsible for ensuring the request contains a valid __RequestVerificationToken header before sending it off to the server. This method returns a promise object as it may relies on an async request to retrieve the token (more details later).

Below is an example of how you could use the ajaxSafePost method to invoke the ‘delete list item’ service.

var recordId = "4ca2e5d1-d0fe-4700-b383-59cee9890392";

var entityReference = {};
entityReference.LogicalName = "new_myentity";
entityReference.Id = "4ca2e5d1-d0fe-4700-b383-59cee9890392";

var ajaxPromise = shell.ajaxSafePost({
	type: "POST",
	contentType: "application/json",
	url: "/_services/entity-grid-delete/" + recordId,
	data: JSON.stringify(entityReference)

ajaxPromise.done(function () {
	alert("Record deleted!");
}); () {
	alert("Something has gone wrong...");

How does ajaxSafePost retrieve the token?

This method first attempts to retrieve the token from an input field on the page. If one is not found, it makes an async request to the URL [portalUrl]/_layout/tokenhtml to request a token.

So… is this supported?

Strictly speaking, since it’s not documented (as far as I’m aware), I’d say this is unsupported. Since the service is fairly loosely coupled to our code however, switching over to a custom service when the need arises should not incur much overhead. You however need to make good judgement based on your own scenario.

So there you have it…

The built-in services are hidden gems that could really streamline your customisation efforts. There are built-in support facilities that make invoking them relatively easy. You however need to consider your scenario carefully as these are not documented, and therefore may change without notice.

I have not had a chance to test whether they also work on CRM Portal online. That is a to-do for the near future.


Posted in Adxstudio, CRM, CRM Portal | 4 Comments

Changing Quick Find to perform ‘contains’ search in CRM

OOTB CRM Quick Find automatically appends a wildcard character (*) to the end of your query, and therefore effectively performs a ‘begins with’ search. If you searched for ‘Canberra’ for example, you’d find ‘Canberra Hospital’, ‘Canberra College’, etc., but you won’t find ‘The Awesome Pub of Canberra’.

To perform a ‘contains’ search, you would need to explicitly include the wildcard character at the start of your query, e.g. ‘*Canberra’. I suspect it was done this way for performance reasons. This however may not be the best user experience in some scenarios.

I have added a new feature to the Enhanced Quick Find solution that allows you to automatically add the wildcard character to the start of users’ Quick Find queries. This turns the query to ‘*Canberra*’ for example, and effectively becomes a ‘contains’ search.

What is this Enhanced Quick Find solution?

This is a CRM solution that I have previously developed that allows you to perform Advanced Find-like queries using text in Quick Find. Essentially it allows you to configure an XML that defines how the query should be interpreted and transformed prior to fetching the results. You can read more about this solution here.

So how do I enable this ‘contains’ search thing for Quick Find?

A new attribute, namely prependWildcardToQueryText, has been added to the QueryTransformation element in the configuration schema. Set this attribute to true to have the wildcard character appended to all Quick Find queries for the target entity. Below is a simple example:

	<QueryTransformation prependWildcardToQueryText='true'/>

Where will this work?

This will work in Quick Find for all the entities that you have created a Quick Find Configuration entity for. This will also work when searching within the lookup field/dialog for those entities. This however does not work with the multi-entity search.

Is there any performance impact?

The solution intercepts and transforms search queries. This in its own should have minimal or no performance impact. Depending on the size of your data, and the number of Quick Find columns you have configured for a given entity however, ‘contains’ searches may have some performance impacts comparing to ‘begins with’ searches. You therefore should consider your scenario and deploy this feature selectively.


You can download the solution ZIP here:

Posted in CRM | Leave a comment

Querying many-to-many relationship in CRM Portal using JavaScript

How do you programmatically query an N:N relationship in CRM Portal using JavaScript without developing additional services?

You can do this with FetchXml and Liquid, and a small hack. Here is a good walkthrough of using FetchXml in Liquid to provide a data service in CRM Portal. I will explain how to adapt this to work for N:N relationships and the hack that would be required.

One thing you should understand is that when you create an N:N relationship in CRM, a “Relationship Entity” is also created behind the scene. This relationship entity is the “joining” entity that you would typically find in a normalised database. You can specify the name of this relationship entity when creating the N:N relationship in CRM as shown below.

To query an N:N relationship in CRM Portal, we will use FetchXml/Liquid to query this relationship entity instead of the actual entities on either end of the relationship.

For example, say I have a Degree and a Subject entities with an N:N relationship, and I want to query all the Subjects for a given Degree (retrieving Subject Name and Subject Code). First thing first, the FetchXml would look as follow (bnh_degree_bnh_subject is the name of my relationship entity):


If you use this FetchXml in Liquid as described by the link earlier on in the post however, you will not get any result. This is because FetchXml in Liquid (as of v8) uses Entity Permission. You need to grant Entity Permission for the relationship entity. (I would guess that Entity Permission for Degree and Subject would also be required – although I have not tested it without).

Here is where the small hack comes in. OOTB you cannot create Entity Permission for a relationship entity. To workaround this:

  1. Create an Entity Permission for a random entity. Set the Scope to Global and grant it the Read privilege.
  2. Add appropriate Web Roles to it.
  3. Create a workflow to update the field adx_entitylogicalname of this Entity Permission record to the name of the relationship entity (bnh_degree_bnh_subject in this example).
  4. UPDATE 02/01/2018: Unfortunately you cannot use a workflow to update the field above. This is because the field is read-only on the form, and therefore the workflow editor does not allow you to set a value for it. Some options to workaround this:
    1. Write a simple C# script
    2. Use a Chrome extension to effectively hack the form and edit the field. Below are some options I would recommend:
      1. Dynamics CRM Power Pane
      2. Level Up

That’s it! Your FetchXml/Liquid should now return results!

Is this hack supported?

Strictly speaking, probably not.

Is it likely to stop working in future updates to CRM and CRM Portal?

I’d say no, but you need to make your own judgement.

So in conclusion…

You can query an N:N relationship in CRM Portal using JavaScript without developing additional services. You just need to query the relationship entity, and apply a small hack to grant the required permission.


Posted in Adxstudio, CRM, CRM Portal | 1 Comment

Reduce code duplication between Insert/Edit forms in CRM Portal with CRMQuickDeploy

CRM Portal is an interesting product, in a good way. One thing it doesn’t do very well however, is that a single Entity Form (or Web Form) cannot be used to handle both inserting and editing records for an entity.

This means you’d need a separate form to handle insert, and a separate form to handle edit – even if the two functionalities should work exactly the same way. This creates an issue as you’d need to duplicate any configuration and code associated with this form.

For a while now CRMQuickDeploy has been allowing you to work with code (JS, CSS, HTML, Liquid) for Portal artefacts in Visual Studio. A new feature has now been added to version 3.3 of this tool to help address the code duplication issue in this particular scenario.

New “link item” in CRMQuickDeploy 3.3

As a quick overview, you can now create a “link item” in your Visual Studio project that points to another item. When this “link item” is deployed, the content of the referenced item is used to update the Portal artefact in CRM.

Sound like “Add as Link” that comes OOTB with Visual Studio? Well, yes.. it is pretty much the same idea. “Add as Link” however does not work within the same project OOTB.

Creating “link item” and referencing source item

You can create a “link item” by creating a normal item for a Portal artefact like you normally would, and then append the “.link” extension to it. You specify the source item within the content of the link item using the INI file format. The INI key is sourceItemPath, and the value is the project-relative path to the source item.

So for example, a link item that holds the JavaScript for an Entity Form could be:

Form1 –

To specify its source content (in this case Form1 – Update.js), specify the following in the content of the link item:

sourceItemPath=PortalEntityForms\Form1 – Update.js

A more detailed example

Let say you have two Entity Forms to create and update Application with the following names in CRM:

  • Application Form – Create
  • Application Form – Update

Because OOTB a Web Page can only host one Entity Form, you also have two Web Pages with the following names in CRM:

  • Application Page – Create
  • Application Page – Update

Imagine you have some JavaScript attached to the Entity Form, and also some HTML/Liquid attached to the Web Page. Because the two functionalities (Create and Update Application) should function the same way, you’d need to duplicate the JavaScript and HTML/Liquid across these Entity Forms and Web Pages.

Using link items, your Visual Studio project would look like this:

Application Form – Create.js would contain the actual JavaScript to be deployed as normal.

Application Form – would contain:

sourceItemPath=PortalEntityForms\Application Form – Create.js

When a deployment is triggered on Application Form –, the target artefact will be deduced from the file name of the link item, in this case Application Form – Update. The content however will be drawn from the referenced source item, i.e. Application Form – Create.js.

Likewise, Application Page – Create.html would contain the actual HTML/Liquid to be deployed for the Web Pages.

Application Page – would contain:

sourceItemPath=PortalWebPages\Application Page – Create.html

Which artefact types are supported with link item?

The following artefact types are supported:

  • Web Page (HTML/Liquid, CSS, JS)
  • Entity Form (JS)
  • Web Form Step (JS)

Download CRMQuickDeploy

You can download CRMQuickDeploy from the Visual Studio Marketplace.


Posted in Adxstudio, CRM, CRM Portal, CRMQuickDeploy | Leave a comment