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.
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) [UPDATE: Portal Buddy lives on! Colin has moved his Companion App starter template to his own Git repository]. 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.
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.
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.
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:
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.