Getting a Map with the Virtual Earth Web Service
The most basic element of Virtual Earth - maps. The Virtual Earth AJAX control is pretty simple because you could just copy and paste code into notepad, save it and run it in a browser. Well, the Virtual Earth Web Service (VEWS) is a bit of a different animal. It uses WCF and WSDL to specify service pointers of where you should be getting maps, directions, YP and Collections, and routes. I figured it would be helpful, what with my deep background in MapPoint Web Service which has a similar architecture, to provide some help on how the Virtual Earth Web Service works. So, over the next few weeks I'll post some (hopefully) helpful samples that will get you past some sticking points. We'll start with just getting a map. I should mention that because I work at Microsoft, these samples will be in ASP .Net (C#), so hopefully understanding the logic will help you translate to whatever language you're working with. If you only do JavaScript / Web Development, you're going to need some more books, because you have some learning to do.
With the VEWS, it is required that all users authenticate. So, you'll need to sign up for a developer account, then authenticate your usage with our HTTP Digest authentication scheme.
First thing we'll need to do is add the Imagery Service. This uses Windows Communication Foundation (WCF), which is "a set of .NET technologies for building and running connected systems. It is a new breed of communications infrastructure built around the Web services architecture. " Ohhh, scary. Uh, no. Basically, it makes it easier for you to not have to worry about where to make your service calls to.
Add the Imagery Service
You can add the imagery service in Visual Studio by going to Website | Add Service Reference and entering the imagery service URI into the address box, then hitting go. It should pull up the reference points in the service with two supported methods (aka Operations) - GetImageryMetaData() and GetMapUri(). Give it a name at the bottom - I named mine ImageryService.
Add New Web Form
You'll need a web page to contain your map, so add a web form to your project - Website | Add New Item | Web Form. I named mine Map.aspx.
Add Image to Your Web Form
VEWS returns the URI for a map image. So, you'll want to have an image placeholder there. Do this by dragging an image object from the toolbox onto your web form. You can resize it to the size you need by dragging the corners.
Authenticate
I'm not going to show you how to authenticate here, but I thought it important to point something out. Although this is a server request, the authentication still requires a token. That wouldn't be a challenge, but the token requires the user's IP so here's how to do it.
I create a class called "Authentication.cs"
In the class I put the authentication I wrote about in my Authentication and Tokens with Virtual Earth post except for one change.
Authentication.cs
using VEWSStaging;
/// <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://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;
}
}
We'll get the IP in the from the Maps.aspx page in the next step.
Requesting a Map
Now, I used most of the code from the SDK so it would help you longer term - teach a man to fish..... Also, I don't use error handling, so for production applications you definitely want to add checks. Here's the code that works for authenticating via my Authentication Class and passing the IP (UserHostAgent) to get the token (yes, token is required). I set the options for the map (center point, zoom level, map style, image height and image width) then request the URI for the map. You'll pass that URI down into the image you dropped on your web page, and you're done!
Map.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Map.aspx.cs" Inherits="Map" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
<title>VEWS Map</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
<asp:Image ID="Image1" runat="server" Height="480px" Width="600px" />
</body>
</html>
Map.aspx.cs
using System;
using System.Collections;
using System.Configuration;
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 ImageryService;
public partial class Map : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string myToken = Authentication.Authenticate(Page.Request.UserHostAddress);
ImageryService.MapUriRequest myMapURIRequest = new MapUriRequest();
myMapURIRequest.Credentials = new ImageryService.Credentials();
myMapURIRequest.Credentials.Token = myToken;
myMapURIRequest.Center = new ImageryService.Location();
myMapURIRequest.Center.Latitude = 37.42196783438708;
myMapURIRequest.Center.Longitude = -122.084039747715;
ImageryService.MapUriOptions myMapURIOptions = new ImageryService.MapUriOptions();
myMapURIOptions.Style = ImageryService.MapStyle.AerialWithLabels;
myMapURIOptions.ZoomLevel = 17;
myMapURIOptions.ImageSize = new ImageryService.SizeOfint();
myMapURIOptions.ImageSize.Height = (int)Image1.Height.Value;
myMapURIOptions.ImageSize.Width = (int)Image1.Width.Value;
myMapURIRequest.Options = myMapURIOptions;
ImageryService.ImageryServiceClient imageryService = new ImageryService.ImageryServiceClient();
ImageryService.MapUriResponse myMapURIResponse= imageryService.GetMapUri(myMapURIRequest);
string MapURI = myMapURIResponse.Uri;
Image1.ImageUrl = MapURI;
}
}
I did this in the Page_Load method, but you can certainly request a map from any web form object and event. When it's all said and done, you get this lovely aerial photo with labels returned to you in .JPEG format and rendered onto a blank page. You'll want to just build your application around it as needed.
I've been getting the question recently about the advantages of VEWS over AJAX. Perhaps this is a post in and of itself, but from a feature perspective:
- VEWS (SOAP) is a server to service model (AJAX is client to service). This means you'll get the map image before your web page is sent to the client. You can control the image and ensure it's there before sending it down to the client.
- VEWS provides static images (on the fly), so you can insert them anywhere that support HTTP requests - mobile devices, JavaScript disabled browsers - or insert them into other documents such as PDFs.
- If you're using MapPoint Web Services, you can finally move over to a similar architecture with almost complete feature parody, but get the "pretty" maps and aerial photos.
- JavaScript is a lightweight scripting language which is great for fast web development, but for heavier applications requiring back end integration you can use VEWS with .Net, Java and any other language that works with HTTP.
SOAP is so clean.
CP
Comments
Anonymous
September 28, 2008
Chris, The URL for the image seems to have a placeholder for the token: myMapURIResponse.Uri {token} Are we supposed to manually replace this with the actual token? John.Anonymous
September 28, 2008
The comment has been removedAnonymous
September 28, 2008
The comment has been removedAnonymous
October 02, 2008
Hi Chris Thanks for your webcast! Just a follow up on this post. I built a mobile website that display a map using the method you presented. Now I would like to add some arrows to pan the map. So I was wondering: is there any way to get the bounding rectangle of an image returned by the VEWS? That way I could find the coordinates of the sides to recenter my current view. Thanks! JohannAnonymous
October 03, 2008
Thanks for the code! Your examples are a great jump start for me. I am new to working with Virtual Earth and my colleague and I were checking out these samples. We had to modify your example to use ImageryService instead of ImageryServiceClient to get it working for us using VS 2005 and the common service staging url. Also had to set the Latitude and LongitudeSpecified to true for the center in the URI request as well as the Height and WidthSpecified attributes to true for the image size in the URI options. I am unclear as to why we would have to do it this way though. Any clarification would be appreciated.Anonymous
October 06, 2008
The comment has been removedAnonymous
October 06, 2008
The comment has been removedAnonymous
October 07, 2008
Here's the answer, http://msdn.microsoft.com/en-us/library/bb259689.aspxAnonymous
October 31, 2008
The comment has been removedAnonymous
November 02, 2008
Hello! I need to get a BirdsEyeView Map for a specific location (I have the latitude and the longitude of the location). I have used the GetImageryMetadata function. My problem is that the Url that this function is returning me is composed from multiples titles. I have put together this titles and composed the image map. But my problem is that I don't know how to get the url image for my location, not the whole map. image I want only my specific location image. The size of the image must be 240px Height and 320px Width. Could you please help me with this? Thank you, Mihaela.Anonymous
November 10, 2008
The comment has been removedAnonymous
November 12, 2008
Hello Chris, Thank you for your answer. Mihaela.Anonymous
December 16, 2008
Mihaela, I have created a utility class in C# that takes a desired boundary area & image size returns an object with the VE zoom level required to fit that boundary, the centre point & the lat/lng of the corners of the image. I agree, it would be lovely to get this from the map service, but it's a good second best. I'm too busy to try & blog about it now, but mail me (my details are in my profile) and I'll send you the code. BenAnonymous
January 29, 2009
First, thank you Chris for the code it works fine. It was very helpful for me to getting started with the VE Imagery Service. I use the VE Web Service (ImageryServiceClient) and therefrom the GetMapUri Method to get a static Map of an Arial Imagery. But know I’ve got a problem. I’ve lat/long of the corners of a location and the Image size for the Arial Image I want. I could calculate the center point of this location but I don’t know the VE Zoomlevel, which is required to fit that boundary rather the corners. Is there any possibility to calculate the Zoomlevel for the static map I want? Or has anybody else another idea to solve my problem?Anonymous
January 30, 2009
The comment has been removedAnonymous
January 31, 2009
I kept getting some image size (height/width) = 0 errors so I added some specoified tags which solved it. myMapURIOptions.ImageSize.Height = (int)Image1.Height.Value; myMapURIOptions.ImageSize.Width = (int)Image1.Width.Value; myMapURIOptions.ImageSize.WidthSpecified = true; myMapURIOptions.ImageSize.HeightSpecified = true; myMapURIRequest.Options = myMapURIOptions; ImageryService.ImageryService imageryService = new ImageryService.ImageryService();Anonymous
February 02, 2009
Thank you for the quick answers. I've posted my question on the MSDN Virtual Earth Forum too and got from Richard_Brundritt these link: http://rbrundritt.spaces.live.com/blog/cns!E7DBA9A4BFD458C5!488.entry Perhaps somebody helps it too!