Displaying pushpins in Bing Maps Silverlight control using GeoRSS feeds

In this post I will briefly explain how to add pushpins in the Bing Maps control using a GeoRSS feed. Although there are many ways of adding pushpins (or any geographic shape for that matter) on a Bing Maps backdrop, I have found this by far the easiest and most flexible.

So assuming you have a spatial table (in this example the table is stored in a SQL Server 2008 database, but any database could be used) containing the points you want to plot. A sample of the table is shown below:

I wont go into any details on how to create a Silverlight project and implement Bing Maps, there are plenty of good examples around. You can start here or here.  Instead, we will first focus on how to create the GeoRSS handler to retrieve the shape data from the table. To do this, right-click on your Web project and select Add->New Item->Generic Handler and name it GeoRSSHandler.ashx.

Replace the default contents in the GeoRssHandler.ashx file with the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;
namespace GeoRSSAndBing.Web
{
///
/// Summary description for GeoRSSHandler
///
public class GeoRSSHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string connStr = ConfigurationManager.ConnectionStrings["spatialDB"].ToString();
context.Response.ContentType = "text/xml";
string type = context.Request["type"];
//Build the GeoRSS feed
System.Text.StringBuilder rssOutput = new System.Text.StringBuilder("");
rssOutput.AppendLine("");
rssOutput.AppendLine("");
rssOutput.AppendLine("");
rssOutput.AppendLine("POIS");
rssOutput.AppendLine("");
rssOutput.AppendLine("" + System.DateTime.Now + "");
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.Text;
if (type == "POI")
{
//Change this statement depending on your settings
cmd.CommandText = "select Eva_Event_ID,EVA_EVENT_TYPE, EVA_EVENT_DESCRIPTION, shape.AsGml() as GeomGml from pois_wgs84";
}
//TODO: Add logic to handle lines and polygons
SqlDataReader sqlGeomRdr= cmd.ExecuteReader();
while (sqlGeomRdr.Read())
{
//Create an element for this row
rssOutput.AppendLine("");
//Set title and description
if (type == "POI")
{
rssOutput.AppendLine("" + sqlGeomRdr["EVA_EVENT_ID"].ToString() + "");
rssOutput.AppendLine("");
rssOutput.AppendLine("");
}
//TODO: Add logic to handle lines and polygons
rssOutput.AppendLine("");
//Get the geography instance GML from column 2
string gml= sqlGeomRdr["GeomGml"].ToString();
//Append the gml: prefix to all the elements due to VE parsing behavior
if (type == "POI")
{
gml = gml.Replace("<Point", "<gml:Point");
gml = gml.Replace("pos", "gml:pos");
gml = gml.Replace("</Point", "</gml:Point");
}
//TODO: Add logic to handle lines and polygons
Add the elements to the output XML
rssOutput.AppendLine(gml);
//Close and elements
rssOutput.AppendLine("");
rssOutput.AppendLine("");
}
rssOutput.Append("");
context.Response.Write(rssOutput.ToString());
}
catch (Exception ex)
{
throw ex;
}
finally
{
conn.Close();
}
}

Next, add a [Show Locations] button in your XAML such as:

<Button Cursor=”Hand” Width=”195″ Height=”25″ HorizontalAlignment=”Left” Content=”Show Locations” x:Name=”b1″ Margin=”2,10,0,1″ Click=”b1_Click”></Button> 
 
 The implementation of the Onclick event in the code behind will call the handler we just created asynchronously i.e.:
 
 private void b1_Click(object sender, RoutedEventArgs e)
 {
   Uri url = new Uri(“../GeoRSSHandler.ashx?type=POI”, UriKind.Relative);  WebClient client = new WebClient();  
    client.DownloadStringCompleted +=new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); 
   client.DownloadStringAsync(url);
 } 

Finally, the downloadString Event handler code is the bit that draws the pushpins on the map:

 void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{ if (e.Error == null)

{ StringReader stream = new StringReader(e.Result); 

 XmlReader reader = XmlReader.Create(stream); 

 string gmlURI = http://www.opengis.net/gml&#8221;;map.Children.Clear();

 while (reader.Read()){

   if (reader.NodeType == XmlNodeType.Element)  {

    if (reader.NamespaceURI == gmlURI && reader.Name == reader.Prefix + “:pos”)

   {

      string[] loc = reader.ReadInnerXml().Split(” “.ToCharArray()); 

      double lat = Double.Parse(loc[1]); 

      double lon = double.Parse(loc[0]); 

      Pushpin p = new Pushpin();p.Location =new Location(lat, lon);map.Children.Add(p);
  }}}}} Next, compile and run your application. Assuming you set the initial Bing Map extent correctly, (i.e. around the area where your points are), clicking on the [Show Locations] button should display your points on Bing Maps using the Default pushpin.

The great thing with this approach, is that you can easily add logic to either add other shape types such as polygons or lines, or retrieve data from other databases by simply amending the code in the GeoRSS handler.

9 thoughts on “Displaying pushpins in Bing Maps Silverlight control using GeoRSS feeds

  1. Error 1

    ‘silverlightmap.Web.GeoRSSHandler’ does not implement interface member ‘System.Web.IHttpHandler.IsReusable’

    SIR, i faced this error when compile my program. what should i do sir? THX for reply!

  2. for spatial table, i should store longitude and latitude? can i get an example for spatial table? thank in advance. =)

  3. Yes, since we are talking about Bing Maps the coordinates would need to be in Lat/Lon. For SQL Server it doesn’t really matter if the spatial column is of type geography. You can also define it as geometry
    This is a simple example of creating a spatial table :
    CREATE TABLE mySpatialTable
    ( id int IDENTITY (1,1),
    shapes geometry);
    GO

    And then to insert into the table, use something like:

    INSERT INTO mySpatialTable (shapes)
    VALUES (geometry::STPointFromText(‘POINT(22.95709, 40.6135782878 )’, 0));
    GO

    Hope this helps.

  4. sorry for disturbing again sir.

    i have created a database named spatialDB with table named dbo.mySpatialTable, and i have followed above example to insert my data.But i still can not to get the location after pressing [show locations].

    what should i put in context.Response.ContentType = “text/xml”;
    (text/xml means i should insert a .xml file with data?)

    this is my cmd.CommandText = “select id,shapes.AsGml() as GeomGml from dbo.mySpatialTable”;

    (p/s i am a newbie in C# and bing mapping.)

  5. ContentType is fine as text/xml. You are retrieving the data as gml which is an xml superset.
    Just put a breakpoint on the client_DownloadStringCompleted function and make sure that SOMETHING get returned and that the code passes trhough the Pushpin creation bit:
    Pushpin p = new Pushpin();
    p.Location = new Location(lat, lon);
    map.Children.Add(p);
    If that works fine make sure your coordinates are valid. Remember that Bing displays in WGS84 so in order to plot something on the map it must be within the valid coordinate range. If for example your point has 1000,2000 as XYs this will never get plotted in Bing maps.

  6. 1)“../GeoRSSHandler.ashx?type=POI”
    2)“http://www.opengis.net/gml”
    sir, i do not understand what does this link refer to. =(

    thank for reply! =)

    1. Hi Lim,
      1. When you click the button, the GeoRSSHandler.ashx will be called with a parameter of type and a value of POI. Which means you can later change the logic in the GeoRSSHandler.ashx code to deal with polygons, lines, etc.
      2. The XML string that gets returned includes this namespace. This is just some extra validation to make sure we are reading a GML-format string

  7. sir. GeoRSSHandler.ashx.cs is not set as Start Page so i cant get the complete url to insert at Uri uri = new Uri(…) any alternative way sir?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s