Some time ago, I did some experiments with Virtual Earth control and its features. I especially liked the GeoRSS integration because it allowed very simple, straightforward, non-astronauts like me to do some very nice mashups.

WCF support for creating RSS feeds is great, but at that time I wanted an even higher level abstraction to hide the details of GeoRSS specific items, so I wrote a simple library that would precisely do that.

Yesterday I found a couple of hours to put this library to work on a more meaningful scenario. Guess which application I extended with it…yes! LitwareHR :-).

This is what I did on my version of the “geo enabled” LitwareHR:

1- I modified the existing RSS feed of “Open Positions” to include geo tags (using the library). If you open the source if the feed on an XML editor it will show:

<rss version="2.0" xmlns:a10="http://www.w3.org/2005/Atom">
  <channel>
    <title>Open positions for tenant_2716236</title>
    <description>Open Positions</description>
    <item>
      <title>code_0</title>
      <description>&lt;strong&gt;id&lt;/strong&gt;: bb9afd1c-d956-4e24-b8b2-c85ceb343aa2 &lt;/br&gt;&lt;strong&gt;location&lt;/strong&gt;: location_0 &lt;/br&gt;&lt;strong&gt;postedOn&lt;/strong&gt;: 6/27/2008 4:40:11 PM &lt;/br&gt;</description>
      <link>
http://www.litwarehr.com/tenant_2716236/public/Careers/JobDetail.aspx?positionId=bb9afd1c-d956-4e24-b8b2-c85ceb343aa2</link>
      <georss:point xmlns:georss="
http://www.georss.org/georss">46.3118415003616 -122.177581787109</georss:point>
    </item>
    <item>
      <title>code_4</title>
      <description>&lt;strong&gt;id&lt;/strong&gt;: babbc272-c2ed-4e06-8a1a-cf9af26df79b &lt;/br&gt;&lt;strong&gt;location&lt;/strong&gt;: location_4 &lt;/br&gt;&lt;strong&gt;postedOn&lt;/strong&gt;: 6/27/2008 4:40:33 PM &lt;/br&gt;</description>
      <link>
http://www.litwarehr.com/tenant_2716236/public/Careers/JobDetail.aspx?positionId=babbc272-c2ed-4e06-8a1a-cf9af26df79b</link>
      <georss:point xmlns:georss="
http://www.georss.org/georss">46.3006945810683 -122.185478210449</georss:point>
    </item>
  </channel>
</rss>

Notice the geo:point elements.

2- I added a new field to the standard, shared Position entity named “geoLocation":

image

I modified the provisioning process to create this field for me for each new tenant (see the GetDefaultPosition method in ProvisioningDataModel.cs under LitwareHR.Portfolio.DataModel.Sitka project)

3- I added a new page under “Job Search”, named JobsMap.aspx, accessible to anybody. This requires changing the SiteMap of the public web site:

<siteMapNode>
        <siteMapNode url="~/Careers/Default.aspx" title="Careers">
            <siteMapNode url="~/Careers/JobSearch.aspx" title="Job Search" description="Context" roles="*">
        <siteMapNode url="~/Careers/JobsMap.aspx" title="Jobs Map" description="Context" roles="*"/>

4- I added a generic handler that acts as a proxy to the RSS feed (this is needed because VE will not pull feeds coming from a different domain the control comes from. (See here for details):

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class maphandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Headers.Add("Pragma","no-cache");
        context.Response.Headers.Add("Cache-Control", "no-cache");
        string geoRssUrl = string.Format( @"
http://services.litwarehr.com/UnSecureHost/feeds.svc/rss/{0}/openPositions", Helpers.TenantAlias );
        WebRequest request = WebRequest.CreateDefault(new Uri(geoRssUrl));
        WebResponse response = request.GetResponse();

        string geoRssContent;
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            geoRssContent = reader.ReadToEnd();

        context.Response.ContentType = "text/xml";
        context.Response.Write(geoRssContent);
    }

5- The JobsMap web page simply embeds the VE control and gets the RSS data from the handler above (which as said, is a proxy for the real RSS feed):

image

The script in the page is:

var map   = null;
function GetMap()
{
   map = new VEMap("myMap");
   map.LoadMap(new VELatLong(46.3081, -122.1928), 12);
   var l = new VEShapeLayer();
   var veLayerSpec = new VEShapeSourceSpecification(VEDataType.GeoRSS,"maphandler.ashx",l);
   map.ImportShapeLayerData(veLayerSpec, null);
}

6- I modified the “AddPosition” page so there’s a “map editor” to capture Longitude and Latitude information and copy it to the geoLocation field. Whenever you click on the map below, the coordinates are captured and placed on the geoLocation field:

image

There’s still some work to be done on the layout and general UI, but the basics are there. I’m planning to upload the whole LitwareHR solution to CodePlex TFS soon and all these additions will go with that, so stay tuned.