Geocoding with the Virtual Earth Web Service

For those of you who may want to get access to the 85 million unique rooftop or parcel centroid accurate points we’ve aggregated in the Virtual Earth Web Service (VEWS), I figured it was only fair that I post a little something to help move you along. Hopefully, this helps you get past a sticking point in your application development. Also, I did all of this on staging so everyone who has an account can do this.

Okay, so, first things first, you need to authenticate – see my post Authentication and Tokens with Virtual Earth for authentication. You’ll need a token to use any part of the VEWS and there’s a good explanation on how to do that for VEWS in my other post (and information on getting a map) – Getting a Map with the Virtual Earth Web Service, but I’ll copy the code to be nice.

The application consists of 3 files – Authentication.cs (a class file for getting me a token); Geocoding.aspx (the UI file for adding web parts); and, Geocoding.aspx.cs (the code behind file where the magic happens). As for my code, it’s only meant to get you up and running to understand architecture – it is not production code. You’ll want error handling and try catches and all the good stuff – this is just the meat and potatoes.

Authentication.cs

using System;
using System.Data;
using System.Configuration;
using VEWSStaging; //VEWS is a reference to http://staging.common.virtualearth.net/find-30/common.asmx

/// <summary>
/// Authenticating for VE Tokens
/// </summary>
public class Authentication
{
    public static string strVEWSToken;
    public static string Authenticate(string strIP)
    {
        CommonService commonService = new CommonService();
        commonService.Url = “https://staging.common.virtualearth.net/find-30/common.asmx”;
        commonService.Credentials = new System.Net.NetworkCredential(“XXXX”, “YYYY”);

        // Create the TokenSpecification object to pass to GetClientToken.
        TokenSpecification tokenSpec = new TokenSpecification();

        // Use the Page object to retrieve the end-client’s IPAddress.
        tokenSpec.ClientIPAddress = strIP;

        // The maximum allowable token duration is 480 minutes (8 hours).
        // The minimum allowable duration is 15 minutes.
        tokenSpec.TokenValidityDurationMinutes = 480;

        // Now get a token from the Virtual Earth Platform Token service.
        strVEWSToken = commonService.GetClientToken(tokenSpec);
        return strVEWSToken;
    }
}

Next, I’ll need to set a reference to the geocoding service (WCF) – Website | Add Service Reference. I named my service “GeocodeService” which you can see has two methods – Geocode and ReverseGeocode.

image 

Next, we’ll need to add UI elements to Geocoding.aspx. I added a Label (as a title), a Text box (to input addresses or places), a Button (to submit the data) and a Table (to store the results). When I’m done, Geocoding.aspx looks like this…

Geocoding.aspx

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”Geocoding.aspx.cs” Inherits=”Geocoding” %>

<!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 runat=”server”>
    <title>CP’s Geocoding Page</title>
</head>
<body>
    <form id=”form1″ runat=”server”>
    <div>
        Enter a location</div>
    <asp:TextBox ID=”TextBox1″ runat=”server” Height=”20px” Width=”375px”></asp:TextBox>
    <asp:Button ID=”Button1″ runat=”server” Height=”21px” onclick=”Button1_Click”
        Text=”Geocode!” Width=”80px” />
    <asp:Table ID=”Table1″ runat=”server” Height=”475px” style=”margin-top: 0px”
        Width=”500px”>
    </asp:Table>
    </form>
</body>
</html>

And now for the magic. We’ll use these elements to make a service request to VEWS to submit the data in the text box and geocode the location. I’ll take the entire response and break up each part so you can see most of what gets returned in the response. Make sure you add a reference to the GeocodeService we added above.

Geocoding.aspx.cs

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using GeocodeService;

public partial class Geocoding : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        //Get user IP for token
        string token = Authentication.Authenticate(Page.Request.UserHostAddress);
        //Instantiate geocode request
        GeocodeRequest myGeocodeRequest = new GeocodeRequest();
        //Instantiate credentials for geocode request
        myGeocodeRequest.Credentials = new GeocodeService.Credentials();
        //Add token to geocode request
        myGeocodeRequest.Credentials.Token = token;
        //Using GeocodeRequest.Query so we don’t need a structured request – just single box
        myGeocodeRequest.Query = TextBox1.Text;
        //Instantiate confidence filter – I just want one filter
        ConfidenceFilter[] myConfidenceFilter = new ConfidenceFilter[1];
        //Instantiate filter
        myConfidenceFilter[0] = new ConfidenceFilter();
        //!Had to specify Geocode Service because Confidence is defined also in Imagery Service!
        //Setting confidence to low so I get maximum results
        myConfidenceFilter[0].MinimumConfidence = GeocodeService.Confidence.Low;
        //Instantiate Geocode options
        GeocodeOptions myGeocodeOptions = new GeocodeOptions();
        //I only want at most 5 results
        myGeocodeOptions.Count = 5;
        //Pass in my confidence filter
        myGeocodeOptions.Filters = myConfidenceFilter;
        //Pass in my geocode options
        myGeocodeRequest.Options = myGeocodeOptions;
        //Instatiate geocode service client for connection to VEWS
        GeocodeServiceClient myGeocodeServiceClient = new GeocodeServiceClient();
        //Physically making VEWS request!
        GeocodeResponse myGeocodeResponse = myGeocodeServiceClient.Geocode(myGeocodeRequest);
        //Loop through results to pull out response and put into a table
        //I’ll only get 1 response, but it could have multiple results
        for(int i = 0; i < myGeocodeResponse.Results.Length; i++)
        {
            TableRow tRow = new TableRow();
            Table1.Rows.Add(tRow);
            TableCell tCell0 = new TableCell();
            tCell0.VerticalAlign = VerticalAlign.Top;
            tRow.Cells.Add(tCell0);
            tCell0.Text = “Formatted Address = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.FormattedAddress;
            tCell0.Text += “<br> Address Line= “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.AddressLine;
            tCell0.Text += “<br> Locality = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.Locality;
            tCell0.Text += “<br> Admin District = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.AdminDistrict;
            tCell0.Text += “<br> Postal Code = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.PostalCode;
            tCell0.Text += “<br> Country = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.CountryRegion;
            tCell0.Text += “<br> District = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.District;
            tCell0.Text += “<br> Postal Town = “;
            tCell0.Text += myGeocodeResponse.Results[i].Address.PostalTown;
            tCell0.Text += “<br> Confidence = “;
            tCell0.Text += myGeocodeResponse.Results[i].Confidence;
            tCell0.Text += “<br> Display Name = “;
            tCell0.Text += myGeocodeResponse.Results[i].DisplayName;
            tCell0.Text += “<br> Entity Type = “;
            tCell0.Text += myGeocodeResponse.Results[i].EntityType;
            tCell0.Text += “<br> Altitude= “;
            tCell0.Text += myGeocodeResponse.Results[i].Locations[i].Altitude;
            /* If there are multiple response types, the latitude, longitude and
             * Calculation methods will have more than one result in their array. This
             * is where you’ll want to differentiate them to use either interpolated,
             * rooftop or parcel centroids depending on how accurate you want them. */
            for (int j = 0; j < myGeocodeResponse.Results[i].Locations.Length; j++)
            {
                tCell0.Text += “<br> Latitude = “;
                tCell0.Text += myGeocodeResponse.Results[i].Locations[j].Latitude;
                tCell0.Text += “; Longitude = “;
                tCell0.Text += myGeocodeResponse.Results[i].Locations[j].Longitude;
                tCell0.Text += “; (“;
                tCell0.Text += myGeocodeResponse.Results[i].Locations[j].CalculationMethod;
                tCell0.Text += “)”;
            }
        }
    }
}

The end results is a nice little parsing of some address information returned from VEWS:

image

There isn’t any difference in the geocoding results you get back between VEWS and the Virtual Earth AJAX control. Both now have rooftop and parcel centroid geocoding points totaling 85 million in the United States. Now, if I can just figure out what’s up with the space between my text box and my table….[FIXED - tCell0.VerticalAlign = VerticalAlign.Top; ]

CP

Join the conversation

12 comments
  1. Anonymous

    We had to modify this code to use GeocodeService instead of GeocodeServiceClient to instatiate the service connection to VEWS. Not sure why this would be the case? Using VS 2005 and the common service staging url

  2. Anonymous

    Hi CP,

    Thanks for publishing this sample code. I have having problems when invoking myGeocodeServiceClient.Geocode(myGeocodeRequest). Even though I was able to successfully obtain a client token, the VirtuL Earth service is returning an expection:

    Credentials are either invalid or unspecified

    Any idea why this might be happening?

    Thanks,

    Chuck

  3. Chris Pendleton

    Chuck – Did this ever get resolved? We had issues with Staging for a week after launch that have been resolved. Let me know.

    CP

  4. Anonymous

    Hi Chris,

    I am facing the same problem as Chuck. Can you please let me know if it got resolved(and how)?

    Thanks in advance.

  5. Chris Pendleton

    Anujkiran,

    Login to the Customer Service Site and validate your credentials.

    CP

  6. Anonymous

    Hi Chris,

    I am creating a Web Cloud Service having one Web Role.

    I have added the necessary references for Authentication and for Geocode Service but i get an exception while creating instance saying:

    "An error occurred creating the configuration section handler for system.serviceModel/bindings: That assembly does not allow partially trusted callers. (C:Usersvinayak_bhosaleDocumentsVisual Studio 2008ProjectstestVEtestVEtestVEbinDebugtestVE.csxrolesWebRoleweb.config line 137)"

    When I create a standard web application it works. Is this problem associated with Cloud Service. Please tell me how to solve this problem.

    Thanks in Advance.

  7. Anonymous

    Hi Chris,

    Thanks for your reply.

    Can you please post the code you created for your blog named "Virtual Earth on Windows Azure" or may be upload them on your sky drive.

  8. Anonymous

    Bing is  a  really  overlord!!    support Bing~~

  9. christopher.zernik

    Hi,

    I'm having problems when invoking GeocodeServiceClient.Geocode(GeocodeRequest). Even though I was able to successfully obtain a client token, I'm getting back an expection:

    Credentials are either invalid or unspecified

    Any idea why this might be happening?

    I'm also using staging.

    Thanks,

    Chris

  10. Chris Pendleton

    @Christopher.zernik – You're missing valid credentials. :) Seriously, though, you should switch to Bing Maps Keys. The token system is being phased out and you can use keys like an application ID: bingmapsportal.com.

    CP

Comments are closed.