Tag Archives: Window Azure

Setting up a Microsoft Cloud trial

CRM Online based solutions often run across the broader Microsoft Cloud, not just CRM Online alone.  As they say, a picture is worth a thousand words.  So here’s a picture that hits home this point at a high level.

image

To help people get started trying this environment out, I’ve created a video that walks you through setting up a trial for CRM Online, Office 365, and Microsoft Azure where all the services are provisioned for Single Sign On (SSO) under a single Azure Active Directory tenant and provide shared administration. 

@devkeydet

Authenticating to an Azure hosted web service from CRM Online Sandbox code

UPDATE (14MAR2013): Uploaded a modified sample which addresses storing credentials in secure config and adds comments around how to encrypt those credentials.  While I show a synchronous plugin in the demo for simplicity of the walkthrough, you should always evaluate whether your plugin logic can fire asynchronously if the action doesn’t require that the user see the result of the action immediately after the record is saved.  Calling an external system from a synchronous plugin can have negative side effects for both user experience and tight coupling with the external system.  When you absolutely must use a synchronous plugin, make sure your code is short lived and try to put your azure web role in a data center as close to your CRM Online data center as possible to minimize network latency.  You should also weigh the pros / cons of using this approach over the inherent Azure Service Bust capabilities Dynamics CRM provides which I talk about in my Integrating with systems behind a firewall from CRM Online using Windows Azure Service Bus Relay post.  While the context of my post is talking to systems behind a firewall, you can also use Azure Service Bus as a mechanism to integrate with a web service running in Windows Azure.  As of the CRM Online December 2012 Service Update and Update Rollup 12, Dynamics CRM includes new support for Windows Azure persistent queues, use of the updated Windows Azure portal to configure ACS, and synchronous plug-in support for posting to the service bus. 

Scenario:

“I need to execute some code from a plugin which requires full trust.  CRM Online doesn’t give me the ability to run full trust code so I want to put my full trust code behind a web service running in a Windows Azure Web Role.  However, every approach I attempt to use to authenticate from the plugin to the web service fails due to sandbox issues.”

While I thought I covered this in my Design for Online post, I learned that my assumptions were incorrect.  I was under then impression that the approach I mention explained in the SharePoint Online and Windows Azure: Developing Secure BCS Connections using WCF Services post which uses UserNamePasswordValidator class would work in CRM Online.  I swear I had it working at one point.  That’s what they all say:).  I recently tried it again and discovered that the client code (the code running in the plugin) required full trust.  I couldn’t figure out a way to get this working in full trust.  I still don’t know why this requires full trust and my attempts at finding an explanation internally at Microsoft came up short.  If someone else has gotten this approach to work, then I would love to know what I am missing. 

Anyway, I had originally been going down a SOAP based approach.  I actually had a sample working from a sandboxed plugin using custom SOAP headers similar to what’s described here.  If you are adamant about wanting to use SOAP, then take a look.  If there’s sufficient comments asking for a SOAP based example, then I will try to find the time to write a post about it.  However, what I realized after I got it all working was that the aforementioned approach is complex and hard to follow.  I saw this as an opportunity to take advantage of the ASP.NET Web API.  I think you’ll find the ASP.NET Web API approach more optimal for this scenario because:

  • We want as efficient communication as possible between CRM Online and the Windows Azure web role.  REST+JSON is the most efficient way I know.
  • ASP.NET Web API makes it really easy to use JSON as the serialization format.
  • It’s pretty easy to implement basic authentication for ASP.NET Web API based services.
  • Basic authentication can be used from a sandbox plugin

Before watching this walkthrough, make sure you go through or at least understand the following ASP.NET Web API walkthroughs:

http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api

http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web-api-that-supports-crud-operations

http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

http://www.asp.net/web-api/overview/security/basic-authentication

Watch the following video once you’ve gotten up to speed using ASP.NET Web API:

The video won’t make much sense if you don’t spend the time understanding ASP.NET Web API.  The code sample I show in the video is available here:

http://sdrv.ms/15LCSax

@devkeydet

Calling CRM from ASP.NET using impersonation to ActOnBehalfOf the logged in user

UPDATE: Please review the comments for this post.  There is a better, easier way to do this using OAuth that works with both the SOAP and REST/OData service.

Sometimes you need to run ASP.NET code outside of Dynamics CRM to achieve your goals.  This usually manifests itself either as a page embedded in CRMs main content area which is accessible via a link in the sitemap similar to the following:

 

image

Another place this is often used is embedding external content through an IFrame in a CRM form.  The general approach is covered in the SDK:

Implement Single Sign-on from an ASPX Webpage or IFRAME

Walkthrough: Single Sign-on from a Custom Web Page

Of course, your code will usually need to call back into Dynamics CRM through the organization (web) service to do things like CRUD on CRM data, etc.  In this scenario, you want CRM to execute code under the context of the logged in user.  The CRM SDK covers how to do this here:

Impersonate Another User

Sample: Impersonate Using the ActOnBehalfOf Privilege

See my CRM Online & Windows Azure Series post for a walkthrough of the Single Sign On (SSO) configuration.  The goal of this post is to bring all of these concepts together in as simple of a “hello world” style code sample as possible.  The sample code is actually the code for the embedded page in the screenshot above (called ActOnBehalfOf.aspx).  The solution is made up of an ASP.NET web form, some code behind the web form, and a helper class I built.  In order to get this code to compile, you are going to have to add the necessary .NET assembly references and fix some of the namespaces.  I’ll leave that exercise to you.

ActOnBehalfOf.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ActOnBehalfOf.aspx.cs" Inherits="AdfsEnabledReportViewerWebRole.ActOnBehalfOf" %>

 

<html>

    <head runat="server">

        <title></title>

    </head>

    <body>

        <form id="form1" runat="server">

            <div>

                <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">

                    <Columns>

                        <asp:BoundField DataField="Id" HeaderText="Id" />

                        <asp:BoundField DataField="Name" HeaderText="Name" />

                    </Columns>

                </asp:GridView>

            </div>

        </form>

    </body>

</html>

ActOnBehalfOf.aspx.cs:

 1: using System;

 2: using System.Linq;

 3: using Microsoft.Xrm.Client;

 4: using Microsoft.Xrm.Sdk.Client;

 5:  

 6: namespace AdfsEnabledReportViewerWebRole

 7: {

 8:     public partial class ActOnBehalfOf : System.Web.UI.Page

 9:     {

 10:         protected void Page_Load(object sender, EventArgs e)

 11:         {

 12:             var contextConnection = ActOnBehalfOfHelper.CreateContextAndConnection();

 13:             CrmConnection conn = contextConnection.Connection;

 14:             OrganizationServiceContext ctx = contextConnection.Context;

 15:  

 16:             // CallierId is what forces CRM to execute the API calls within the security context of the CRM User

 17:             conn.CallerId = ActOnBehalfOfHelper.GetCallerId();

 18:  

 19:             var accountQuery = from a in ctx.CreateQuery<Account>()

 20:                         select new Account

 21:                         {

 22:                             Id = a.Id,

 23:                             Name = a.Name

 24:                         };

 25:  

 26:             var accounts = accountQuery.ToList();

 27:  

 28:             GridView1.DataSource = accounts;

 29:             GridView1.DataBind();

 30:         }

 31:     }

 32: }

If you’ve reviewed the resources in this post, then ActOnBehalfOf.aspx and ActOnBehalfOf.aspx.cs should be pretty self explanatory.  It’s a page with a GridView.  The code behind queries CRM for data using the organization service.  Note that Account from line 19 comes from a class file where I used crmsvcutil.exe to generate the class.  I always use Erik Pool’s approach to only generate classes I need in my code.  I digress.  The code sets the CallerId property of the CrmConnection object instance before executing the code.  By doing this, CRM will execute all calls made to through the OrganizationServiceContext instance as the CRM user based on the CallerId value passed in.  CallerId is the GUID of the CRM user who needs to be impersonated.  The ActOnBehalfOfHelper does the real work to get the proper GUID based on the claims available to the ASP.NET page.  Specifically, it uses the UPN claim value to find the CRM user.  Once the CRM user is found, the code returns the Id of the CRM user as a GUID. 

ActOnBehalfOfHelper.cs:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using Microsoft.IdentityModel.Claims;

using Microsoft.Xrm.Client;

using Microsoft.Xrm.Client.Services;

using Microsoft.Xrm.Sdk.Client;

 

namespace AdfsEnabledReportViewerWebRole

{

    public static class ActOnBehalfOfHelper

    {

 

// ReSharper disable InconsistentNaming

        private const string CRM_CALLERID = "CRM_CALLERID";

// ReSharper restore InconsistentNaming

 

        public static ContextConnection CreateContextAndConnection()

        {

            var contextConnection = new ContextConnection();

            // Connect to CRM with a single named user (i.e. system account / trusted subsystem model) who has the ActOnBehalfOf privelege

            contextConnection.Connection =

                CrmConnection.Parse("Url=[YOUR_ORG_URL];Username=[YOUR_USERNAME];Password=[YOUR_PASSWORD]");

            contextConnection.Context =

                new OrganizationServiceContext(new OrganizationService(contextConnection.Connection));

 

            return contextConnection;

        }

 

        public static Guid GetCallerId()

        {

            Guid callerId;

            var contextConnection = CreateContextAndConnection();

            var ctx = contextConnection.Context;

 

            // NOTE: I am caching the CallerId to minimize calls to the CRM Organization Service.

            // For production code, you should not store the CallerId in plain text in a cookie.

            // Malicious code, once authenticated, can change the cookie value and execute as another caller.

            // You could apply encryption when creating the cookie and decryption when reading 

            // the cookie value:

            // http://msdn.microsoft.com/en-us/library/windowsazure/hh697511.aspx

            // You could even encrypt/decrypt the cookie name to obfuscate the purpose of the cookie.

            // Alternatively, find a different approach to cache the CallerId value (ASP.NET Session for example)

            // or simply don't cache the CallerId.

 

            HttpCookie callerIdCookie = HttpContext.Current.Request.Cookies[CRM_CALLERID];

 

            // If the cookie exists, reuse the Guid string value to execute the call as the current user

            // If not, then query CRM to get the Guid of the authenticated user based on the upn claim

            if (callerIdCookie == null)

            {

                ClaimCollection claims = ((IClaimsIdentity) HttpContext.Current.User.Identity).Claims;

 

                IEnumerable<Claim> claimQuery = from c in claims

                                                where

                                                    c.ClaimType ==

                                                    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"

                                                select c;

 

                Claim upnClaim = claimQuery.FirstOrDefault();

 

                var userQuery = from user in ctx.CreateQuery<SystemUser>()

                                where user.DomainName == upnClaim.Value

                                select user.SystemUserId.Value;

 

                callerId = userQuery.FirstOrDefault();

                if (callerId == Guid.Empty)

                {

                    // Send HTTP status code of 403

                    // See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

                    HttpContext.Current.Response.StatusCode = 403;

                    HttpContext.Current.Response.End();

                }

 

                string callerIdString = callerId.ToString();

                HttpContext.Current.Response.Cookies.Add(new HttpCookie(CRM_CALLERID, callerIdString));

            }

            else

            {

                callerId = new Guid(callerIdCookie.Value);

            }

 

            return callerId;

        }

    }

 

    public class ContextConnection

    {

        public CrmConnection Connection { get; set; }

 

        public OrganizationServiceContext Context { get; set; }

    }

}

Note the comments in the code.  I am doing some caching of the user GUID in a cookie.  Right now, the cookie and cookie value is in plain text.  As I state, this is done for simplicity of the sample.  Make sure you read the comments and make the proper adjustments to protect access to the CallerID GUID from malicious code/callers.

@devkeydet

Preventing charges for an Azure VM when not in use

When you shutdown an Azure VM, you still get charged for usage.  That’s because the hardware for your VM is still allocated/dedicated to you.  It’s just not being used.  To prevent charges, you can delete the VM.  When you do that, your .vhd file(s) don’t’ get deleted.  Therefore, you can recreate the VM rather quickly when you want to start using it again.  While you can do this manually, it can become tedious depending on how often you need to do it.  The good news is that you can automate this process using PowerShell.  You’ll need to make sure you’ve run through Getting Started with Windows Azure PowerShell first.  Then you can follow the instructions from Importing and Exporting Virtual Machine Settings.  I keep this post handy since I create and delete my VM as needed so I am only charged for the time I am actually using it.

@devkeydet

CRM Online myth busters

DISCMLAIMER: Parts of this blog post contain my opinion and don’t necessarily reflect the opinion of my employer, nor is it an official endorsement by Microsoft of any of the tools / technologies I mention.

I’ve been in my new role, focusing on Dynamics CRM, for about 7 months now.  Having focused on Windows Azure as an evangelist since it was announced at the PDC in 2008, I was very much in “cloud mode” when I joined this team.  WOW, has it really been 4 years since Azure was announced?  Time flies.  Anyway, one of the first questions I had when I joined my new team was “Why aren’t we talking to our customers about CRM Online more?”  The general feedback I got from teammates and partners was that there were a few key things missing that enterprise customers need.  Those things were available on-prem, but not online.  Of course, I wanted to know, very granularly, what these things were.  As I learned about the perceived limitations of CRM Online for enterprise scenarios, I discovered some of them were real, while most were either myths or required one to step back and understand how to design a solution for the cloud.  I also discovered that while I had been immersed in the capabilities of Windows Azure for quite some time, most folks building Dynamics CRM solutions were not.  Windows Azure is an important piece of the CRM Online solution puzzle for certain scenarios.

In the short 7 months I have been focused on Dynamics CRM, CRM Online has come a long way.  Most of the real roadblocks to enterprise adoption have been addressed or will be by the Q2 2012 Service Update (aka R8).  However, many people still have a dated “mental picture” of what can and cannot be done with CRM Online.  It’s human nature to recommend what you know and it’s hard to keep up with the rapid evolution of cloud platforms.  This post is an attempt to dispel some of the common myths I run into about CRM Online so that you know what’s actually possible today (or very soon).  I have heard each one of these myths/objections many times in many conversations throughout the last few months.  In my opinion, the time for enterprise customers to take another serious look at CRM Online is now.

First, have look at the CRM Online home page to understand what the service offers.  After you understand what you get with CRM Online, read on…

 

MYTH: My users can’t authenticate to CRM Online using their Active Directory username and password.

FACT: Since the November 2011 Service Update (aka R7) CRM Online can be configured for Claims-based authentication using your organizations Active Directory Federation Services (ADFS) 2.0 deployment (mentioned about 2:10 minutes into the video).  However, you currently have to request enrollment.  If you don’t already have a Microsoft contact to ask about enrollment and configuration, you can contact the CRM Online Team through their blog

 

MYTH: I can’t deploy custom SQL Server Reporting Services (SSRS) reports to CRM Online.

FACT: You can.  However, your SSRS reports must be FetchXML based.  In order to build FetchXML SSRS reports, you need to install the Microsoft Dynamics CRM 2011 Report Authoring Extension on the same PC in which you have Business Intelligence Development Studio (BIDS) installed.  This adds a Fetch XML data source.  From there, you just follow the directions in Create Custom Reports Using Business Intelligence Development Studio.  SSRS reports in CRM Online are Sandboxed.  See RDL Sandboxing for Microsoft Dynamics CRM Online for more details.  One of the objections I often hear is “but I really want to write my queries in SQL because that’s what I know.”  I “get it,” but for now, FetchXML it is.  For most, I recommend using the Advanced Find feature of the CRM UI to compose the query, then click the Download Fetch XML button. 

image 

For advanced query capabilities of FetchXML that aren’t possible through Advanced Find, you will need to start with Advanced Find, then modify the XML yourself.  See Build Queries with FetchXML for more details.  Personally, I’m not “GUI Query Tool” guy.  I like to write my queries by hand.  Let’s face it, no one wants to learn “yet another query language” which is what you have to do with FetchXML.  I shield myself from this by using LINQ.  I use LINQPad + LINQPad Plugin for Microsoft Dynamics CRM 2011.  The one gotcha is that the plugin doesn’t produce FetchXML.  There’s a feature request here to enhance the plugin to do so.  VOTE it up!  However, through extensibility of LINQPad, I created an extension method to do the conversion.  See Getting FetchXML from LINQPad for more details.

 

MYTH: I can’t deploy custom workflow activities to CRM Online.

FACT: While this is true as of the time I write this blog post, the Q2 2012 Service Update (aka R8) will enable this feature.  COMING VERY SOON.

 

MYTH: I can’t write the kind of code I need to write in plugins because they only run in the sandbox. 

FACT: While it is true, that the sandbox impose certain limitations, there are ways to accomplish your goals.  There are two primary scenarios I get asked:

  • Sandbox plugins can’t use third party libraries. 
    • Consider using ILMerge as a workaround.  Another option is to use the same approach as I will explain for the second scenario below.
  • I need to do something from the plugin that is not permitted within the sandbox.
    • Write a plugin that calls a web service you own running somewhere else, say a Windows Azure web role.  You have just designed a solution that allows you to step out of the sandbox and do what your heard desires.

MYTH: I can’t host a custom ASP.NET web page or web service like I can when I own the CRM Server.

FACT: While this is technically true, you can accomplish the same thing by hosting your web page somewhere else.  See Implement Single Sign-on from an ASPX Webpage or IFRAME for more details.  As you might have already guessed, there’s a section titled “Microsoft Dynamics CRM Online with a Windows Azure Hosted Webpage.”  By doing this you can no longer use window.parent for cross frame communication because you will be in a cross domain scenario. See Cross domain calls to the parent CRM 2011 form.

 

MYTH: CRM Online only gives me 5 GB of storage.

FACT: You can buy additional storage at $9.99 per 1 GB increments.

 

MYTH: I still have to install the email router on a server in my environment.

FACT: While CRM Online doesn’t yet have an email router as part of the service, you do have options.  Not everyone uses or needs the email router.  If you do, one option is to setup the email router using a third party hosting provider that offers admin access to the server they provide you through Remote Desktop.  See Microsoft Dynamics CRM 2011 for E-mail Router Installing Guide for use with Microsoft Dynamics CRM Online for more details.  One way to find a hosting provider is to go to http://dkdt.me/IJluXC and enter “Remote Desktop” in the Narrow Results search box.  If you are considering CRM Online, you are probably doing it because you don’t have to worry about setting up infrastructure.  So it’s probably safe to say you’d prefer an “email router as a service.”  There’s an option for you too.  Have a look at the HubOne Cloud based Email Router for Dynamics CRM Online 2011.  This would be my preference if I were considering CRM Online. 

 

MYTH: I can’t get a backup of my CRM Online database.

FACT: While there is no automated way to do this today, CRM Online customers can request backups of their database(s).  However, I always have a conversation with folks to understand what they are trying to accomplish with a database backup.  Many of the scenarios people think they need database backups for can be addressed without a database backup.  You should always maintain your customizations in a CRM solution package and maintain an export somewhere else as a “backup” of your customizations.  Sometimes people aren’t really looking for a database backup as much as they are looking for a way to import/export data.  CRM Online has the same import/export facilities and web service APIs as the CRM you install yourself.  Therefore, tools such as CozyRoc and Scribe are applicable.

 

MYTH: I can’t integrate with systems behind my firewall from CRM Online.

FACT: While CRM Online doesn’t provide any specific capability to securely cross the internet and talk to systems behind an organizational firewall, you can still do it.  CRM Online is from Microsoft.  Microsoft is a platform company that happens to have a platform that already enables such scenarios.  It’s called Windows Azure.  I address this scenario and others in my CRM Online + Windows Azure = Many Possibilities post.  While these approaches enable "from CRM Online” scenarios, meaning code running inside CRM Online calling out, it’s equally important to understand that some integration needs can be met with data integration that can be achieved through tools such as  CozyRoc and Scribe.  Of course, your scenarios will dictate what integration approach is most appropriate.

MYTH: I can’t optimize query performance by adding custom indexes to the database.

FACT: While there is no automated way to do this today, CRM Online customers can request the addition of indexes to enhance query performance.

MYTH: CRM Online doesn’t have the industry compliance and certifications I need.

FACT: Have a look at Microsoft Dynamics CRM Online: Security Features, Standard Response to Request for Information – Security and Privacy, and Security, Audits and Certifications.  Most people are pleasantly surprised by the certifications CRM Online has and the security measures in place.  The Certifications section of the latest Release Preview Guide states that for the Q2 2012 update, the following certifications will be achieved:

  • Microsoft Data Centers
    • ISO 27001
    • SAS70 Type II
    • Sarbanes–Oxley
  • Microsoft Dynamics CRM Online Service
    • Safe Harbor
    • ISO 27001
    • SSAE 16 SOC1 (Type II)
    • Data Processing Agreement (DPA)
    • EU Model Clauses
    • Business Associates Agreement – enables a company to be Health Insurance Portability and Accountability Act (HIPAA) compliant

 

Please let me know in the comments if you have other “is it possible in CRM Online” questions.  I will either respond in the comments or, if warranted, update this post accordingly.   

@devkeydet

Integrating with systems behind a firewall from CRM Online using Windows Azure Compute and Connect

UPDATE (30MAY2013):  The core concepts in this post still apply.  However, now you have two options Windows Azure Networking or Windows Azure Connect

This post is somewhat of a placeholder.  I have some work to do to get everything in order to create a post/video.  However, I wanted to provide you some insight into what I am planning for this post and some links for those of you who might want to figure it out yourself without waiting on my additional details.  What I plan on showing is how you can leverage an ASP.NET  page running in a Windows Azure Web Role that talks to a SQL Server database running behind a firewall.  The web page will be integrated into a CRM Online solution such that at the end of your interaction with it, the page will pass data from the database to the CRM form to prepopulate information on the form.

If you watch my previous screencast called Hybrid Solutions with Windows Azure Connect, then you will get a basic understanding the Windows Azure Connect piece.  The next step would be to have a look at the Implement Single Sign-on from an ASPX Webpage or IFRAME topic from the CRM 2011 SDK.  You may say to yourself: “but CRM Online doesn’t support Claims-based authentication with ADFS.”  It has since the November 2011 Service Update (mentioned about 2:10 minutes into the video).  However, you currently have to request enrollment.  If you don’t have a Microsoft contact to ask about enrollment, you can contact the CRM Online Team through their blog.  Finally, have a look at Cross domain calls to the parent CRM 2011 form.  The Windows Azure web role will be in a different domain, so we’ll have to handle the passing of data back to the CRM form properly. 

With these three resources, those of you who are adventurous should have enough information to try the scenario out yourself.  Otherwise, stay tuned for me to update this post.

@devkeydet

Integrating with systems behind a firewall from CRM Online using Windows Azure Service Bus Relay

The Windows Azure Service Bus Relay enables applications hosted anywhere with an internet connection to securely call back to applications hosted in your own datacenter behind a firewall.  The CRM 2011 SDK offers documentation on how to use the Windows Azure Service Bus Relay from CRM Online.  Here’s a link to the documentation that describes the scenario:

http://dkdt.me/HOzzrr

The video below demonstrates a working example of the end to end scenario and walks you through the configuration.

http://dkdt.me/HOzy6X 

NOTE: The video shows my WCF service running in a console application for simplicity.  Many will want to host their services in IIS.  See IIS hosting of Wcf Services with Servicebus Endpoints for more details.

@devkeydet

CRM Online + Windows Azure = Many Possibilities

I have spent some time lately working with both potential CRM Online customers and partners who were unaware of the what’s really possible when you combine CRM Online with Windows Azure.  I primarily work with customers/partners building “enterprise” solutions.  I have heard statements like the following:

“I can’t use CRM Online because I have to integrate with systems behind my organizations firewall.”

“I can’t use CRM Online because I need to write custom ASP.NET pages and Web Services that integrate with my solution.”

Since the material available on the topic is slim, I decided to write a series of blog posts and/or videos demonstrating some common scenarios to get your creative juices flowing.  This post will serve as the table of contents.  Therefore, I will update it periodically.  You will find links to the various scenarios below.  Topics without links are posts I have planned.

Integrating with systems behind a firewall from CRM Online using Windows Azure Service Bus Relay

Going outside the CRM Online sandbox using Windows Azure Compute

Integrating with systems behind a firewall from CRM Online using Windows Azure Compute and Connect

More topics to come…

While these topics are specific to CRM Online + Windows Azure, they also present design principles that can be leveraged in an on-premises deployment that will help you architect a solution that can run in whatever deployment model you choose.

Please let me know in the comments if you have any other questions or ideas for a topics in this series.

@devkeydet

Cross domain calls to the parent CRM 2011 form

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.

UPDATE2: You might also be interested in my newer post: Cross domain calls from JavaScript

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. 

The downside of this forced decoupling is that it does add some complexity.  You can’t just drop ASP.NET code in a folder and have everything “just work.”  Setting this configuration up in an on-prem environment using windows authentication without SSL is relatively painless with no apparent side effects.  However, CRM 2011 has quite a bit of flexibility in how it can be configured.  In some of the more advanced configurations, an issue with a commonly used approach in CRM 2011 JavaScript programming will surface.  More and more people will run into this as they move to claims based authentication.  This post is my attempt to help shed some light on the situation and provide an alternative approach.

It is quite common for people to use window.parent from a child page in the companion web site (hosted within an IFrame) to call a JavaScript function written in a web resources hosted in the parent CRM form.  Here’s an example:

window.parent.someFunction(someData);

…where the parent form has a JavaScript web resource that looks like this:

function someFunction(someData)

{

    // 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:

  • You use CRM Online and the companion site is in Windows Azure, Office 365, or any hosting provider for that matter
  • You are using claims based authentication with an internet facing deployment (IFD) 
  • If you are using SSL for your CRM deployment, then you must use SSL for your companion site which means you can’t differentiate the sites by port because they both require 443.  BTW, you can use wildcard certificates and host headers to bind to 443 multiple times on the same server.

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:

  • document.domain only works for sites that are subdomains of the primary domain (ex: a.domain.com and b.domain.com)
  • document.domain won’t work for child pages hosted in Windows Azure, SharePoint Online, or anywhere else that’s not in the domain of your CRM deployment
  • Most importantly, using document.domain has an adverse side effect that causes CRM 2011 functionality to fail in certain scenarios

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:

http://benalman.com/projects/jquery-postmessage-plugin/

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. 

NOTE: I only pass a string message in the sample.  To pass a more rich data structure, I’d recommend using the wildly popular json2.js file to stringify/parse JavaScript Object Notation (JSON) on each end.

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:

  • on-prem with windows authentication
  • on-prem with claims based authentication
  • IFD with claims based authentication
  • CRM Online with Office 365
  • CRM Online with Windows Azure
  • Pretty much anything that has SSO configured

@devkeydet

What does a custom CRM solution look like?

UPDATED with the Grants Manager solution accelerator…

There are many examples that I will be blogging about.  Here is one that uses both Dynamics CRM 2011 Online and Windows Azure or Dynamics CRM 2011 and Windows Server on-prem.

http://311center.codeplex.com/

Microsoft 311 Accelerator for Dynamics CRM 2011

Microsoft 311 Service Center accelerator is an integrated citizen services framework that helps to streamline the processes in a citizen service center. It provides a framework to service citizen requests, provide information, manage back office processing, and utilize resources efficiently. The 311 Service Center accelerator is built on the fully integrated Microsoft Dynamics CRM 2011 and Windows Azure platforms, providing both on-premises and online delivery models.

The second link in this post has a video overview of the accelerator.  You can download the solution, including source code from the CodePlex link.

Another one to look at is:

http://grantsmanager.codeplex.com/

Grants Manager is a solution accelerator designed to help
government organizations and educational institutions to quickly deploy a grant
management system and customize it to their needs. Each deployment will require
tailoring to the specific needs of the organization.

@devkeydet