UPDATE: Added reference to another blog post that does a great job of going into the cross-document / cross-domain issue. Fixed some grammar/typos.
I’ve spoken to some folks recently who built solutions using CRM 4.0 and were fond of the ability to put custom ASP.NET (aspx) pages in the ISV folder. As of CRM 2011, this is a deprecated feature. This has caused a bit of heartache and frustration with those fond of the feature. The CRM 2011 SDK provides guidance on how to address this in the following sections:
Upgrade Code in the ISV folder to Microsoft Dynamics CRM 2011
Implement Single Sign-on from an ASPX Webpage or IFRAME
Walkthrough: Single Sign-on from a Custom Web Page
What you’ll find in the guidance is a new approach that works similarly to the ISV folder approach. The major difference is that your custom ASP.NET pages run in a separate web site, hence a separate IIS Application Pool. The forced decoupling of your code executing in the same context as the CRM Server code is a good thing in my opinion. This is very similar to how plugins run in isolation. By allowing your ASP.NET code to run in-process with the CRM Server code, the 4.0 approach was at the mercy of poorly written code. Your code could actually adversely effect the CRM UI. As I understand it, this happened quite a bit in the 4.0 days. Isolation of your code from CRM code is more resilient. Although probably less often used, an added benefit of this separation of is that you have another boundary that can be scaled independently. Depending on the nature of your code, there may be value in running your stuff on their own servers.
// Do something with someData
The issue surfaces when your companion site is running in a different domain (or even subdomain). Browsers will surface a security error and prevent the call from happening. Why would you run the companion site in a different domain/subdomain? Here are a few reasons:
So what’s the issue? Well you can’t call window.parent unless both pages share the same domain of origin. Now if you are web savvy, you might say “aha, but I can use document.domain on both ends!” And you would be justified in assuming you could. However there are some issues:
It’s important to understand that the cross domain issue has nothing to do with CRM 2011. It has everything to do with how browsers work. As a security measure, they don’t allow you to make cross domain calls. One could argue that you didn’t have to deal with this when the ISV folder was an option. Fair enough, but I’ve already made my case for why the deprecation of the ISV folder was a good thing. If you choose to ignore the fact that the ISV folder has been deprecated, you put yourself or your customer in jeopardy for upgradeability in the future. Don’t to it. Period.
Ok, enough background…how do you make this work if you absolutely must have window.parent.someFunction like interaction from a child page in another domain and a CRM form? There’s an API in modern browsers called window.postMessage. Not all browsers support window.postMessage. However, there’s a handy little library that wraps window.postMessage and includes a fallback mechanism for legacy browsers:
In my tests, I’ve been able to successfully use this approach across a number of scenarios. I’ve created a sample of the approach in action. Here are the instructions to get it working:
If I’ve explained that right, you should have the sample working. The instructions are purposefully vague so they can be applied to the various scenarios this can run in.
There’s another helper library called easyXDM that’s similar to the jQuery postMessage plugin I use in the sample. They both use the same basic approach. I chose jQuery postMessage because it was lighter weight and got the job done. easyXDM is more feature rich and worth looking at as well. There’s a great article here that talks about this whole scenario in even more detail, outside of the CRM context. It also mentions easyXDM at the end.
What’s the lesson here? Don’t use window.parent. Instead, use window.postMessage or the helper library I use in my samples. By doing this, you have a solution that will work in all the major combinations of possible CRM 2011 deployment environments: