Using Custom Extensions to Integrate Bing Maps and Microsoft Dynamics CRM 4.0

Roshan Mehta, 19 August 2010

In my previous post, I showed you a simple way to integrate Bing Maps with Microsoft Dynamics CRM 4.0 using iFrames and address data on a custom Dynamics CRM form. In this post, I will show you how to display a map for an Account record in a custom ASPX page.

The idea behind this integration is to open an Account and click on a custom button on the Account form to pop-up a custom ASPX page to display the map. Firstly, we need to add a custom button to the Account form. To do this, export the ISV Config file and locate the following tag:

<Entity name=”account”>

We want to add the following code beneath this tag.

    <ToolBar ValidForCreate="0" ValidForUpdate="1">

      <Button Icon="/_imgs/ico_18_debug.gif" Url=”/url/to/view-map.aspx" PassParams="1" WinParams="" WinMode="0">

        <Titles>

          <Title LCID="1033" Text="View Map" />

        </Titles>

        <ToolTips>

          <ToolTip LCID="1033" Text="View the map for this Account" />

        </ToolTips>

      </Button>

      <ToolBarSpacer />

    </ToolBar>

Save the file and import it back into Microsoft Dynamics CRM. Refresh the browser for the changes to take effect. Note – if the button still doesn’t appear, make sure that the Custom Menu and Toolbars section has been configured correctly in the Customizations tab under System Settings.

The next thing we need to do is create the custom ASPX page. Add a new web form to your Visual Studio project called view-map.aspx. In the <head> tag of the aspx file, add the following JavaScript:

    <script src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2" type="text/javascript"></script>

    <script type="text/javascript">

        function showMap(address) {

            map = new VEMap('myMap');

            map.LoadMap();

            StartGeocoding(address);

        }

 

        function GeocodeCallback(shapeLayer, findResults, places, moreResults, errorMsg) {

            // if there are no results, display any error message and return

            if (places == null) {

                alert((errorMsg == null) ? "There were no results" : errorMsg);

                return;

            }

 

            var bestPlace = places[0];

 

            // Add pushpin to the *best* place

            var location = bestPlace.LatLong;

 

            var newShape = new VEShape(VEShapeType.Pushpin, location);

 

            var desc = "Latitude: " + location.Latitude + "<br>Longitude:" + location.Longitude;

            newShape.SetDescription(desc);

            newShape.SetTitle(bestPlace.Name);

            map.AddShape(newShape);

        }

 

        function StartGeocoding(address) {

            map.Find(null,    // what

              address, // where

              null,    // VEFindType (always VEFindType.Businesses)

              null,    // VEShapeLayer (base by default)

              null,    // start index for results (0 by default)

              null,    // max number of results (default is 10)

              null,    // show results? (default is true)

              null,    // create pushpin for what results? (ignored since what is null)

              null,    // use default disambiguation? (default is true)

              null,    // set best map view? (default is true)

              GeocodeCallback);  // call back function

        }

    </script>

The showMap function calls the VEMap constructor inside the referenced script. The parameter passed to this function is the id of the <div> tag that you wish to display the map inside. Do not create a <div> tag for the map. We will do this inside the C# code-behind.

Now we need to add some code to the view-map.aspx.cs file. Here’s what the code in the Page_Load handler looks like.

            if (!Page.IsPostBack)

            {

                //connect to crm – see the crm sdk for more information

  CrmService sdk = GetCrmConnection();

 

                //retrieve the address details for the selected account

                Guid id = new Guid(Request.QueryString["id"]);

                if (id != null && id != Guid.Empty)

                {

                    ColumnSet cols = new ColumnSet();

                    cols.Attributes.Add("address1_line1");

                    cols.Attributes.Add("address1_line2");

                    cols.Attributes.Add("address1_city");

                    cols.Attributes.Add("address1_country");

                    account acc = (account) sdk.Retrieve(EntityName.account.ToString(), id, cols);

                    string fullAddress = string.Format("{0} {1} {2} {3}", acc.address1_line1, acc.address1_line2, acc.address1_city, acc.address1_country);

 

                    string div = "<div id='myMap' style='position: relative; width: 400px; height: 400px;'></div>";

                    string script = string.Format("<script type='text/javascript'>showMap('{0}')</script>", fullAddress);

                    ClientScript.RegisterClientScriptBlock(this.GetType(), "myScript1", div);

                    ClientScript.RegisterClientScriptBlock(this.GetType(), "myScript", script);

                }

            }

The reason why I have added the <div id=’myMap’> declaration inside the code-behind file is to ensure that the div is created before the application tries to call the VEMap constructor, otherwise you will receive JavaScript errors.

After you have deployed the custom aspx page, we’re ready to test and see how it works. Create a new Account record and specify the address details.

Next, click on the custom “View Map” button on the Account form toolbar.

Here is the resulting map.

And that’s all there is to it - another nice way to integrate Bing Maps with Microsoft Dynamics CRM 4.0. Stay tuned for future posts where I will show you some more cool ways to integrate the two systems.