I spent last week in Amsterdam attending both eXtreme365 and the User Group Summit, and was lucky enough to get to present three sessions on Dynamics 365 Portal topics. At each one of these sessions, one of the areas that generates the most interest is when I discuss the idea of a Companion App. Companion Apps are a technique you can use to leverage server-side code in your Portal implementation, and since it’s a topic I haven’t really covered on my blog, I thought it was about time.

What is a Companion App?

I believe it was Business Solutions MVP Colin Vermander who coined the term – or at the very least popularized it. In fact, he’s even got a GitHub project to act as a starter template (although I wish the original name of the project, Portal Buddy, had remained). A Companion App is a web application (containing a web service) that you host yourself (either on-premise or in the cloud) that you interact with on the Portal using AJAX calls.

Because you host this app yourself, you have full control over it, including the ability to use server-side code. You can use server-side code to access APIs, including the Dynamics 365 API, or any other API you like. You control what functions your web service makes available to the JavaScript on your Portal.

However, introducing a Companion App to your Portal project is not without its complexities.


As mentioned, you can host the Companion App pretty much anywhere you want, as long as it is accessible to the users of your Portal. That means technically if your Portal is only used by people within your firewall, your Companion App doesn’t need to be publicly accessible. Most of the time we find that organizations either host it using Azure Web Apps, or using an existing on-premise web server.

The Dynamics 365 Portal offering is Software-as-a-Service, so it means there are no servers to maintain. By introducing a Companion App, you’re adding infrastructure to a Portal project that does need to be maintained.

SSL Requirement

This is pretty straight-forward, but still worth mentioning. Since a Dynamics 365 Portal is hosted over HTTPS, any AJAX calls made from the Portal to another service also need to be over HTTPS. If you choose to host somewhere like Azure Web Apps, this shouldn’t be a problem as they include certificates for the *.azurewebsites.net domain, however I thought I’d mention it because if you’re developing locally, it’s important to configure HTTPS properly.

Cross-origin Resource Sharing

Another thing browsers don’t like is when you make an AJAX call to a domain that is different than the original page – this is called Cross-origin Resource Sharing (CORS). For example, if your JavaScript is coming from yourportal.microsoftcrmportals.com, but your AJAX call is to your Companion App hosted at yourcompanionapp.azurewebsites.net, the browser will reject that call unless you perform some additional configuration.

The configuration needs to happen on the server that is receiving the CORS request, so in this case the Companion App. If you’re hosting your app in Azure Web Apps, you can enable CORS directly in the Azure portal, without touching your code at all. Or, if you’re developing an ASP.NET you can add a few lines of code to enable CORS support. Keep in mind that when you enable CORS, you can specify which domains you accept requests from – although you can technically allow all domains, best practice is to limit this to only the domains you require (in this case, the domain of your Portal).


As with most things Portal-related, caching can cause headaches when implementing a Companion App. This is because any cache of the Dynamics 365 data your Companion App may have is different than the Portal cache.

The Portal relies on receiving cache invalidation messages via Azure Event Hub – these messages are triggered based on the Change Tracking feature in Dynamics 365. So it’s important that any relevant entities have Change Tracking enabled to ensure that the cache is updated when data is modified. However, this process isn’t instantaneous, so even when everything is configured properly, you may run into weird issues.

A good example is if you use a Companion App to create a record in Dynamics 365, and then immediately redirect the user to an Entity List that is rendered by the Portal. If the cache invalidation message hasn’t been received by the Portal yet, it’s possible that the record, even though it exists in Dynamics 365, may not appear in the list. A refresh a few seconds later may make the record appear, but that is not an ideal user experience.

I recommend avoid mixing out-of-the-box Portal features with Companion Apps for this reason. If you can segment your functionality in this way, you are less likely to run into odd caching behaviour.


When you log into a Portal, your browser receives a cookie that is then passed to the Portal server on each subsequent request that tells the code who you are. Since cookies are domain-specific, the Companion App doesn’t get the cookie when you make a request to it. Even if it did, the Companion App wouldn’t be able to decrypt the information in the cookie in order to figure out which contact record is associated with the logged in user. So that means we need to figure out a way to share the authentication information with the Companion App, since in most cases it’s important for security to know who the logged in user is.

There are a few different options:

  • If you are using Azure AD B2C for authentication, check out the link above to Colin Vermander’s Companion App starter template. It already supports sharing the authentication of Azure AD B2C users between the Portal and the Companion App.
  • If you are using Azure AD, it is possible to modify Colin’s project to support that scenario as well, as Azure AD and Azure AD B2C are similar enough.
  • If you are using a different authentication provider, I’ve implemented an authentication sharing scheme using tokens and Liquid that could be of some help. I can share more with the community if there is interest.
  • If you can wait, then hopefully this problem will be solved for everyone shortly. This is because the April ’19 release notes have made mention of a new Portal feature that will allow us to obtain a token directly from the Portal that we can use to authenticate the user with our Companion App. This is similar to the technique Colin is using in his project, but will work regardless of the authentication provider you use.

Companion Apps are a great way to extend your Portal beyond the out-of-the-box capabilities. They certainly add complexity to a project, but when used properly they allow you to do almost anything while still leveraging the great capabilities of the Portal product.

The post Dynamics 365 Portal: Custom Server-side Code with a Companion App appeared first on Engineered Code.