Home > Extensions > API-SDK > Workflow > Workflow: Geocode (and correct) Addresses with Bing Maps

Bing Maps are great. You can geocode and correct your addresses. Depending on your level of queries and types of usage you may need to purchase credits to query Bing Maps, but I thought it was pretty straight forward. If you need to get a Bing Maps account, go here.

The thing that makes this great is it is workflow. It is not tied down to an entity. You can use it on your custom entities, you can geocode your addresses, and correct them. You can do address verification and geocoding. You can control what you do using workflow.

Ok, while this isn’t anything complicated, I thought it was a good example of a custom workflow that used an external webservice. Please don’t forget to create a signed key for your project.

Workflow Class:

using System;
using System.ServiceModel;
using System.Text;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using BingWorkflow.BingMapsGeo;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Workflow;
using Microsoft.Win32;

namespace BingWorkflow
{
    [CrmWorkflowActivity("Bing Maps", "Geocode")]
    public class VerifyAddressUsingBingMapsActivity :
        SequenceActivity
    {
        // Activity code goes here. 

        public static DependencyProperty AddressCityProperty = DependencyProperty.Register(
            "AddressCity", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty AddressCountryProperty = DependencyProperty.Register(
            "AddressCountry", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty AddressLine1Property = DependencyProperty.Register(
            "AddressLine1", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty AddressPostalCodeProperty = DependencyProperty.Register(
            "AddressPostalCode", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty AddressStateProperty = DependencyProperty.Register(
            "AddressState", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty BingKeyProperty = DependencyProperty.Register(
            "BingKey", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputCityProperty = DependencyProperty.Register(
            "OutputCity", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputCountryProperty = DependencyProperty.Register(
            "OutputCountry", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputLatitudeProperty = DependencyProperty.Register(
            "OutputLatitude", typeof (CrmFloat), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputLine1Property = DependencyProperty.Register(
            "OutputLine1", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputLongitudeProperty = DependencyProperty.Register(
            "OutputLongitude", typeof (CrmFloat), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputMultipleFoundProperty = DependencyProperty.Register(
            "OutputMultipleFound", typeof (CrmBoolean), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputPostalCodeProperty = DependencyProperty.Register(
            "OutputPostalCode", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        public static DependencyProperty OutputStateProperty = DependencyProperty.Register(
            "OutputState", typeof (string), typeof (VerifyAddressUsingBingMapsActivity));

        [CrmInput("Address City")]
        public string AddressCity
        {
            get { return (string)GetValue(AddressCityProperty); }
            set { SetValue(AddressCityProperty, value); }
        }

        [CrmInput("Address Country")]
        public string AddressCountry
        {
            get { return (string)GetValue(AddressCountryProperty); }
            set { SetValue(AddressCountryProperty, value); }
        }

        [CrmInput("Address Line 1")]
        public string AddressLine1
        {
            get { return (string)GetValue(AddressLine1Property); }
            set { SetValue(AddressLine1Property, value); }
        }

        [CrmInput("Address Postal Code")]
        public string AddressPostalCode
        {
            get { return (string)GetValue(AddressPostalCodeProperty); }
            set { SetValue(AddressPostalCodeProperty, value); }
        }

        [CrmInput("Address State Or Province")]
        public string AddressState
        {
            get { return (string)GetValue(AddressStateProperty); }
            set { SetValue(AddressStateProperty, value); }
        }

        [CrmInput("Bing API Key")]
        public string BingKey
        {
            get { return (string)GetValue(BingKeyProperty); }
            set { SetValue(BingKeyProperty, value); }
        }

        [CrmOutput("City")]
        public string OutputCity
        {
            get { return (string)GetValue(OutputCityProperty); }
            set { SetValue(OutputCityProperty, value); }
        }

        [CrmOutput("Country Or Region")]
        public string OutputCountry
        {
            get { return (string)GetValue(OutputCountryProperty); }
            set { SetValue(OutputCountryProperty, value); }
        }

        [CrmOutput("Latitude")]
        public CrmFloat OutputLatitude
        {
            get { return (CrmFloat)GetValue(OutputLatitudeProperty); }
            set { SetValue(OutputLatitudeProperty, value); }
        }

        [CrmOutput("Line 1")]
        public string OutputLine1
        {
            get { return (string)GetValue(OutputLine1Property); }
            set { SetValue(OutputLine1Property, value); }
        }

        [CrmOutput("Longitude")]
        public CrmFloat OutputLongitude
        {
            get { return (CrmFloat)GetValue(OutputLongitudeProperty); }
            set { SetValue(OutputLongitudeProperty, value); }
        }

        [CrmOutput("Multiple Address Found")]
        public CrmBoolean OutputMultipleFound
        {
            get { return (CrmBoolean)GetValue(OutputMultipleFoundProperty); }
            set { SetValue(OutputMultipleFoundProperty, value); }
        }

        [CrmOutput("Postal Code")]
        public string OutputPostalCode
        {
            get { return (string)GetValue(OutputPostalCodeProperty); }
            set { SetValue(OutputPostalCodeProperty, value); }
        }

        [CrmOutput("State Or Province")]
        public string OutputState
        {
            get { return (string)GetValue(OutputStateProperty); }
            set { SetValue(OutputStateProperty, value); }
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            // Reset Outputs
            OutputLatitude = new CrmFloat();
            OutputLongitude = new CrmFloat();
            OutputLine1 = String.Empty;
            OutputCity = String.Empty;
            OutputState = String.Empty;
            OutputPostalCode = String.Empty;
            OutputMultipleFound = new CrmBoolean {Value = false};

            var key = BingKey;
            if (String.IsNullOrEmpty(key) || key.ToLower() == "registry")
            {
                key = GetAPIKeyFromRegistry();
            }

            // Create Bing Maps Request
            var bingRequest = new GeocodeRequest
                              {
                                  Credentials = new Credentials {ApplicationId = key},
                                  Query = AddressLine1 + ", " +
                                          AddressCity + ", " +
                                          AddressState + ", " +
                                          AddressPostalCode + ", " +
                                          AddressCountry
                              };

            // Filter for High Confidence
            var filters = new ConfidenceFilter[1];
            filters[0] = new ConfidenceFilter {MinimumConfidence = Confidence.High};
            bingRequest.Options = new GeocodeOptions {Filters = filters};

            // Create Client
            GeocodeServiceClient bingClient = null;
            try
            {
                var geoBinding = new BasicHttpBinding(BasicHttpSecurityMode.None)
                                 {
                                     Name = "BasicHttpBinding_IGeocodeService",
                                     CloseTimeout = new TimeSpan(0, 1, 0),
                                     OpenTimeout = new TimeSpan(0, 1, 0),
                                     ReceiveTimeout = new TimeSpan(0, 10, 0),
                                     SendTimeout = new TimeSpan(0, 1, 0),
                                     AllowCookies = false,
                                     BypassProxyOnLocal = false,
                                     HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                                     MaxBufferSize = 65536,
                                     MaxBufferPoolSize = 524288,
                                     MaxReceivedMessageSize = 65536,
                                     MessageEncoding = WSMessageEncoding.Text,
                                     TextEncoding = Encoding.UTF8,
                                     TransferMode = TransferMode.Buffered,
                                     UseDefaultWebProxy = true
                                 };

                var geoEA =
                    new EndpointAddress("http://dev.virtualearth.net/webservices/v1/geocodeservice/GeocodeService.svc");

                bingClient = new GeocodeServiceClient(geoBinding, geoEA);

                var bingResponse = bingClient.Geocode(bingRequest);

                if (bingResponse.Results != null && bingResponse.Results.Length > 0)
                {
                    if (bingResponse.Results.Length > 1)
                    {
                        OutputMultipleFound.Value = true;
                    }

                    var bingResult = bingResponse.Results[0];

                    if (bingResult.Locations != null && bingResult.Locations.Length > 0)
                    {
                        var bingLocation = bingResult.Locations[0];
                        OutputLatitude.Value = bingLocation.Latitude;
                        OutputLongitude.Value = bingLocation.Longitude;
                    }

                    var bingAddress = bingResult.Address;

                    OutputLine1 = bingAddress.AddressLine;
                    OutputPostalCode = bingAddress.PostalCode;
                    OutputCountry = bingAddress.CountryRegion;

                    OutputCity = String.IsNullOrEmpty(bingAddress.PostalTown)
                                     ? bingAddress.Locality
                                     : bingAddress.PostalTown;
                    OutputState = String.IsNullOrEmpty(bingAddress.AdminDistrict)
                                      ? bingAddress.District
                                      : bingAddress.AdminDistrict;
                }
            }
            catch (Exception ex)
            {
                throw new WorkflowTerminatedException(
                    "There was an error openning the connection to Bing Maps.", ex);
            }
            finally
            {
                // Close the client
                if (bingClient != null)
                {
                    bingClient.Close();
                }
            }

            return base.Execute(executionContext);
        }

        private static string GetAPIKeyFromRegistry()
        {
            // Opening the registry key
            var key = Registry.LocalMachine;
            if (key != null)
            {
                key = key.OpenSubKey("Software\\Microsoft Geocoder");
            }

            return key != null ? key.GetValue("APIKey").ToString() : null;
        }
    }
}

One Response to “Workflow: Geocode (and correct) Addresses with Bing Maps”

Comments (3)
  1. HI,
    Could you include a picture of what you mean? I am one of many copy paste programmers, but would like to see the result of your programming in some type of image:)

    Thank you..

    PS.. I just recently discovered your blogg, and now I am sticking to it:)!!

  2. I was wondering if you could help me?

    We are using the Bing Spatial Data Services from the selections of Bing Map API’s. We are sending a group of addresses and say that there is an address in Brooklyn NY but the address is supposed to be New York, NY the service will not bring anything back. Now if you use the maps it will just automatically change it to New York, NY. Is there a parameter that can be set to automatically update this address if this happens?

    I have been thrown into this project last minute so I am not that familiar with all of this. Is this someting you can help me with or point me in the right direction.

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2011 MSCRM Blogger

This site does not necessarily represent the views of Microsoft. The material posted on this blog are provided AS-IS, and you are to use the content at your own risk. Some of the code and information on this site may use unsupported methods. If you experience any problems using the information provided through this website, please post a comment and we will do our best to assist you, however, we can in no way guarantee support or resolution.

Microsoft Dynamics®, Silverlight®, Visual Studio®, and the corresponding logos are a registered trademarks owned by Microsoft Corporation. MSCRM Blogger has made every effort to supply trademark information about company names, products, and services mentioned on this blog. All third party trademarks are the property of their respective owners. Any rights not expressly granted herein are reserved.