Dynamics CRM & Bing Maps Integration

02.17.12

Many of the clients we speak with wish to have Microsoft Bing map integrations, but want to use standard address fields instead of latitude / longitude. Using CRM 2011’s OData query capabilities and Microsoft’s Bing web API, this can be achieved using a single HTML page within the CRM solution file. Madrona Solution Group has developed a simple HTML file that works the out-of-the-box contact entity using the standard address fields.

 
 
Including this file as part of your Microsoft Dynamics CRM 2011 solution is a straightforward process. To do so, follow these 7 steps:
  1. Get a Microsoft Bing Map key. Make sure to review and understand Bing Map’s licensing and pricing information.
  2. Save the script below as a HTML file. This file contains the JSON / OData scripts that query CRM for the address fields.
  3. Update the HTML file with the Microsoft Bing key received in step 1. Within the HTML script file, it is on line 149. 
  4. Upload the HTML file as a web resource file in your CRM 2011 solution giving it a unique name. Since this sample file is specific to the contact form, I recommend ‘Contact Bing Map’.
  5. Customize the contact form:
  • Add the web resource added in step 4.
  • Include the value “Id” as a custom parameter
  • Check ‘Pass record object-type code and unique identifier as parameter’
 
6.  Save and publish all customizations.
7.  Save and close all forms. 
 
There are a few key things to note about the script:
  • Partial addresses can be used without additional coding to this script. The variable sAddress is built up the values returned by the OData query from CRM. Microsoft Bing Maps understands the partial address and will render the address based on the information passed. 
  • The function retrieveAddress contains a JSON query which has the CRM fields returned for the Bing Map. JSON queries are case sensitive and work with the schema names of the entity. Since the HTML page can be a bit challenging to debug, we recommend that if you face challenges working with JSON queries that you use a separate JavaScript file to verify the script.
  • The icon shown as the pushpin can be a custom icon pulled from the CRM resource library. This especially helpful when using this script for custom entities. Simply change the variable sIconURL value to reflect the value of the value to the web resource URL in the library
This HTML source code can easily be customized to be used for additional entities including custom. To do this:
  1. Update the OData query defined in the variable sQuery to return the appropriate address fields. 
  2. Update the pushpin icon to use the web resource associated with the custom entity. 
  3. Update the function retrieveAddressReqCallBack to check for the values returned from the OData query to build up the variable sAddress.
  4. Follow steps 3 through 6 from above.
Contact Bing Map HTML Source Code:
 
		<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
    <meta http-equiv="X-UA-Compatible" content="IE=8" />  
    <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>  
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>  
    <script type="text/javascript" src="ClientGlobalContext.js.aspx"></script>  
    <script type="text/javascript">  

 /**************************************************************************  
 Parse the ID of the CRM record
 **************************************************************************/  
        var sID;  
        var context = Xrm.Page.context || GetGlobalContext();   
        var serverUrl = context.getServerUrl();  

        function getParameters(values, unescapeValues) 
		{  
            var oArr;  
            var sParameters = new Array();  
            var vals = ('?' == values.charAt(0) ? values.substr(1) : values).split("&");  
            for (var i in vals) {  
                oArr = vals[i].split("=");  
                if (oArr[0] == 'id') {  
                    sID = oArr[1].substr(3, 36);  
                }  
            }  
        }  
  
 /**************************************************************************  
 Constructing the JSON objects and query
 **************************************************************************/  

        function loadMap() 
		{  
            getParameters(location.search, true);  
            if (sID != null) 
			{  
                retrieveAddress(sID);  
            }  
        }  
  
        function retrieveAddress(Id) 
		{  
            var serverUrl = GetGlobalContext().getServerUrl();
            var sQuery = serverUrl + "/XRMServices/2011/organizationData.svc/ContactSet?$select=ContactId, FullName, Address1_Line1, Address1_Line2, Address1_City, Address1_StateOrProvince, Address1_PostOfficeBox&$filter=ContactId eq guid'{" + Id + "}'";
            var sIconURL = "http://localhost:5555/_imgs/ico_16_2.gif";
            var request = new XMLHttpRequest();
            request.open("GET", sQuery, false);//sync
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            request.send();

			retrieveAddressReqCallBack(request, sIconURL); 
            
        }  
		
        function retrieveAddressReqCallBack(retrieveReq, sIconURL) 
		{  
			
			//Success  
			var retrievedAddress = JSON.parse(retrieveReq.responseText).d;  
            var popupTitle = "Contact Name";
            var sAddress = "";

            if (retrievedAddress.results[0].FullName != null)
            {
                popupTitle = retrievedAddress.results[0].FullName;
            }
            
            
            if (retrievedAddress.results[0].Address1_Line1 != null)
            {
                sAddress = retrievedAddress.results[0].Address1_Line1;
            }

            if (retrievedAddress.results[0].Address1_Line2 != null)
            {
                if (sAddress != "")
                {
                    sAddress = sAddress + "," + retrievedAddress.results[0].Address1_Line2;
                }
                else
                {
                    sAddress = retrievedAddress.results[0].Address1_Line2;
                }
            }

            if (retrievedAddress.results[0].Address1_City != null)
            {
                if (sAddress != "")
                {
                    sAddress = sAddress + "," + retrievedAddress.results[0].Address1_City;
                }
                else
                {
                    sAddress = retrievedAddress.results[0].Address1_City;
                }
            }

            if (retrievedAddress.results[0].Address1_StateOrProvince != null)
            {
                if (sAddress != "")
                {
                    sAddress = sAddress + "," + retrievedAddress.results[0].Address1_StateOrProvince;
                }
                else
                {
                    sAddress = retrievedAddress.results[0].Address1_StateOrProvince;
                }
            }

            if (retrievedAddress.results[0].Address1_PostOfficeBox != null)
            {
                if (sAddress != "")
                {
                    sAddress = sAddress + "," + retrievedAddress.results[0].Address1_PostOfficeBox;
                }
                else
                {
                    sAddress = retrievedAddress.results[0].Address1_PostOfficeBox;
                }
            }

			map.Find(null, sAddress, null, null, 0, 1, false, false, false, false, 
			
			function (shapeLayer, results, places, moreResults, error) 
			{  
                var place = places[0];  
				var pushpin = new VEPushpin('1', place.LatLong,  
											sIconURL,   
											popupTitle, //Title  
											sAddress  //Address  
											);  
				map.AddPushpin(pushpin);  
                map.SetCenterAndZoom(place.LatLong, 13);  

			});  
                
        }  
    </script>  
</head>  
<body>  
    <div id="map" style="position:absolute; top:0px; left:0px; width:100%; height:100%;"/>  
</body>  
</html>  
<script type="text/javascript">  
    
    var map = new VEMap("map");  
    map.SetCredentials("INSERT BING MAP KEY HERE");  
    map.LoadMap();  
      
    //Resize the map  
    window.onresize = function (event) { map.Resize(document.body.clientHeight); };  
    window.onresize(null);  
    loadMap();  
</script>

« Back to index