
I’ve waited and waited for months now for Microsoft to add the popular KML / KMZ file formats directly to their library, but have seen no indication from them that it is coming anytime soon. This is a big deal for sites or desktop applications that offer Bing Maps, but can’t find a way for their visitors to display KML files on their local machines on your map page. The closest thing is a method by which you place the KML file on a publicly accessible web server, then call a Bing Maps remote function (passing it the URL of the file to be converted) and then displaying the returned results.
We decided to make the most of a good thing and create a simple way to allow our customers to display their local KML files on our publicly accessible embedded Bing Maps websites and applications. Microsoft requires that the KML to be decoded be Internet accessible so they can get the file, decode it with their proprietary methods, and simply return the data as a series of VEShape objects.
To accomplish this, our map software has an “Import KML” button that brings up a file selection dialog. The user selects the file which calls a server side C# function:
1: WebClient wcUp = new WebClient();
2: byte[] responseArray = wcUp.UploadFile("http://myserver.com/uploadkmlfile.aspx", tbFilename.Text);
3: WebHeaderCollection myWebHeaderCollection = wcUp.ResponseHeaders;
4: // Now read the filename from our header response
5: string sNewFilename = myWebHeaderCollection.Get(0);
6: mapBrowser.Document.InvokeScript("LoadKMLMap", new object[] { "http://myserver.com/KML_Temp/" + sNewFilename});
In line 2, we pass the URL of an .aspx file that exists on our server that handles the upload. Line 5 is important because it sets the variable sNewFilename to the unique name given the file on our server. Here is the sample UploadKMLFile.aspx and corresponding code so you can see what is happening:
1: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="UploadKMLFile.aspx.cs" Inherits="UploadKMLFile" %>
2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3: <html xmlns="http://www.w3.org/1999/xhtml">
4: <head runat="server">
5: <title></title>
6: </head>
7: <body>
8: <form id="form1" runat="server">
9: <div>
10: </div>
11: </form>
12: </body>
13: </html>
As you can see, the .aspx code is just a dummy page that relies on the C# code-behind to handle the upload:
1: using System.IO;
2: using System.Net;
3: using System.Web;
4:
5: public partial class UploadKMLFile : System.Web.UI.Page
6: {
7: protected void Page_Load(object sender, EventArgs e)
8: {
9: foreach(string f in Request.Files.AllKeys)
10: {
11: string sNewName = string.Format("{0}{1}{2}{3}{4}.kml",
12: DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond);//file.FileName);
13: HttpPostedFile file = Request.Files[f];
14: file.SaveAs(Server.MapPath("~/KML_Temp/") + sNewName);
15: Response.Headers.Add("Newname", sNewName);
16: }
17: }
18: }
The C# code behind (UploadKMLFile.aspx.cs) takes the file and saves it to a unique name in our ~/KML_Temp directory. We then add a response header which is the new name of the uploaded file. That name is then returned to the calling function on our map web page.
Line 6 of the first code block (server side C# function) then takes that returned new name and calls a JavaScript function on our map page called LoadKMLMap. That function looks like this:
1: var lNew = new VEShapeLayer();
2:
3: function LoadKMLMap(sFile)
4: {
5: var veLayerSpec = new VEShapeSourceSpecification(VEDataType.ImportXML, sFile, lNew);
6: map.ImportShapeLayerData(veLayerSpec, onFeedLoad, true);
7: }
8:
9: function onFeedLoad(feed)
10: {
11: var iCount=0;
12: for(var i=0;i<lNew.GetShapeCount();i++)
13: {
14: iCount++;
15: var shape = lNew.GetShapeByIndex(i);
16: if(shape.GetCustomIcon() == null) // we have no icon
17: {
18: shape.HideIcon();
19: shape.SetCustomIcon("<img src='http://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif' />");
20: }
21: }
22: map.AttachEvent("onmouseover", ShapeInfo);
23: alert('KML collection loaded. There are '+ feed.GetShapeCount()+
24: ' items in this list. ' + iCount + ' actual');
25: }
26:
27: function ShapeInfo(e)
28: {
29: if(e.elementID != null)
30: {
31: X = e.mapX;
32: Y = e.mapY;
33: var point = map.PixelToLatLong(new VEPixel(X,Y));
34: shape = map.GetShapeByID(e.elementID);
35: map.ShowInfoBox(shape, point);
36: }
37: }
NOTES: Make sure to set the permissions on your KML_Upload directory so that IIS can write the stream to your server. The temporary filename given to each uploaded file ensures that the file is unique and that users looking at files of the same name on their machines will not have the same name on our server, thus avoiding conflict of files.
THE Definitive guide for Bing Maps! Now available on Amazon.com!
If you need assistance or have questions in setting up your application / web site to import KML files, please send us a message and we will schedule a call and let you know how we can help!