The CityView Application

The CityView Application

The Web application pictured in Figure 11-11 CityView is a novel and graphic example of a Web service client. The Web service that it connects to is the Microsoft TerraService (http://terraservice.net/terraservice.asmx), which is a Web service front end to the Microsoft TerraServer database. You can read all about TerraServer and TerraService at http://terraservice.net. TerraServer is one of the world s largest online databases. Inside it are photographs and maps of much of Earth s surface, made available to the public through a partnership between Microsoft and the U.S. Geological Survey. TerraService exposes TerraServer s content via Web methods. There are 16 Web methods in all, with names such as ConvertPlaceToLonLatPt and GetTile. As you might expect, TerraService was written with the Microsoft .NET Framework. Its WSDL contract is available at http://terraservice.net/terraservice.asmx?wsdl.

Before you can run CityView, you need to install it on your Web server. Here s how:

  1. Copy CityView.aspx and CityView.ashx from the CD that came with this book to the virtual directory of your choice.

  2. Create a subdirectory named bin in the directory that you copied CityView.aspx and CityView.ashx to. Then copy TerraService.dll to the bin directory. TerraService.dll is a DLL containing a TerraService proxy class named TerraService.

Figure 11-11

CityView showing an aerial view of San Francisco.

Now that CityView is installed, try it out by calling up CityView.aspx in your browser. Enter a city name (for example, New York ) and pick a state. Then click Show Image. After a brief pause, the specified city appears at the bottom of the page. If CityView is unable to fetch the image you requested, it responds by displaying Image not available in place of the image. That could mean you entered a city that doesn t exist. Or it could mean that TerraService is temporarily down or your Internet connection is taking a nap.

You can zoom in and out by selecting different scales. The default scale is 8 meters. Choose a smaller number to zoom in or a larger number to zoom out. For a great aerial view of the San Francisco peninsula that includes an overhead shot of the Golden Gate Bridge, enter San Francisco, CA and choose a scale of 32 meters.

How CityView Works

CityView consists of three files:

  • CityView.aspx

  • CityView.ashx

  • TerraService.dll

CityView.aspx is a Web form that defines CityView s user interface. Its source code appears in Figure 11-12. The user interface consists of a TextBox for typing city names, a DropDownList for selecting states, a RadioButtonList for choosing scales, and a Button for posting back to the server and fetching images. It also includes an Image control whose ImageUrl property is programmatically initialized following each postback. Here s the code that assigns a URL to the Image control:

MyImage.ImageUrl = builder.ToString ();

If you enter Redmond, WA, and accept the default scale of 8 meters, the string assigned to ImageURL looks like this:

CityView.ashx?city=Redmond&state=WA&scale=8

which sets the stage perfectly for a discussion of the second component of CityView: namely, CityView.ashx.

CityView.ashx is an HTTP handler. Specifically, it s an HTTP handler that generates and returns a bitmap image of the location named in a query string. When we deployed an HTTP handler in Chapter 8, we coded the handler in a CS file, compiled it into a DLL, and dropped the DLL into the application root s bin directory. We also registered the handler using a Web.config file. CityView.ashx demonstrates the other way to deploy HTTP handlers. You simply code an IHttpHandler-derived class into an ASHX file and include an @ WebHandler directive that identifies the class name and the language in which the class is written:

<%@ WebHandler Language="C#"  %>

When a client requests an ASHX file containing a WebHandler class, ASP.NET compiles the class for you. The beauty of deploying an HTTP handler in an ASHX file is that you don t have to register the handler in a CONFIG file or in the IIS metabase; you just copy the ASHX file to your Web server. The downside, of course, is that you must test the handler carefully to make sure ASP.NET can compile it.

The CityViewImageGen class inside CityView.ashx (Figure 11-12) generates the images that CityView.aspx displays. Its heart is the ProcessRequest method, which is called on each and every request. ProcessRequest calls a local method named GetTiledImage to generate the image. Then it returns the image in the HTTP response by calling Save on the Bitmap object encapsulating the image:

bitmap.Save (context.Response.OutputStream, format);

Should GetTiledImage fail, ProcessRequest returns a simple bitmap containing the words Image not available instead of an aerial photograph. It also adjusts the format of the bitmap to best fit the type of content returned: JPEG for photographs, and GIF for bitmaps containing text.

GetTiledImage uses three TerraService Web methods:

  • ConvertPlaceToLonLatPt, which converts a place (city, state, country) into a latitude and longitude

  • GetAreaFromPt, which takes a latitude and longitude and an image size (in pixels) and returns an AreaBoundingBox representing the image boundaries

  • GetTile, which takes a tile ID (obtained from the AreaBoundingBox) and returns the corresponding tile

A tile is a 200-pixel-square image of a particular geographic location. To build larger images, a TerraService client must fetch multiple tiles and stitch them together to form a composite. That s how GetTiledImage generates the 600 x 400 images that it returns. It starts by creating a Bitmap object to represent the image. Then it uses Graphics.DrawImage to draw each tile onto the image. The logic is wholly independent of the image size, so if you d like to modify CityView to show larger (or smaller) images, find the statement

Bitmap bitmap = GetTiledImage (city, state, res, 600, 400);

in CityView.ashx and change the 600 and 400 to the desired width and height.

The third and final component of CityView is TerraService.dll, which contains the TerraService proxy class named TerraService. CityView.ashx s GetTiledImage method instantiates the proxy class and uses the resulting object to call TerraService s Web methods:

TS.TerraService ts = new TS.TerraService ();

TerraService.dll was compiled from TerraService.cs, which I generated with the following command:

wsdl /namespace:TS http://terraservice.net/terraservice.asmx

The namespace was necessary to prevent certain data types defined in TerraService s WSDL contract from conflicting with data types defined in the .NET Framework Class Library. Once TerraService.cs was created, the command

csc /t:library terraservice.cs

compiled it into a DLL.

CityView.aspx

<html> <body> <h1>CityView</h1> <hr> <form runat="server"> <table cellpadding="8"> <tr> <td> City </td> <td> <asp:TextBox  Width="100%" RunAt="server" /> </td> <td> <asp:RequiredFieldValidator ControlToValidate="City" ErrorMessage="*" Display="static" Color="red" RunAt="server" /> </td> </tr> <tr> <td> State </td> <td> <asp:DropDownList  Width="100%" RunAt="server"> <asp:ListItem Text="AL" RunAt="server" /> <asp:ListItem Text="AK" RunAt="server" /> <asp:ListItem Text="AR" RunAt="server" /> <asp:ListItem Text="AZ" RunAt="server" /> <asp:ListItem Text="CA" RunAt="server" />

 <asp:ListItem Text="CO" RunAt="server" /> <asp:ListItem Text="CT" RunAt="server" /> <asp:ListItem Text="DC" RunAt="server" /> <asp:ListItem Text="DE" RunAt="server" /> <asp:ListItem Text="FL" RunAt="server" /> <asp:ListItem Text="GA" RunAt="server" /> <asp:ListItem Text="HI" RunAt="server" /> <asp:ListItem Text="IA" RunAt="server" /> <asp:ListItem Text="ID" RunAt="server" /> <asp:ListItem Text="IL" RunAt="server" /> <asp:ListItem Text="IN" RunAt="server" /> <asp:ListItem Text="KS" RunAt="server" /> <asp:ListItem Text="KY" RunAt="server" /> <asp:ListItem Text="LA" RunAt="server" /> <asp:ListItem Text="MA" RunAt="server" /> <asp:ListItem Text="MD" RunAt="server" /> <asp:ListItem Text="ME" RunAt="server" /> <asp:ListItem Text="MI" RunAt="server" /> <asp:ListItem Text="MN" RunAt="server" /> <asp:ListItem Text="MO" RunAt="server" /> <asp:ListItem Text="MS" RunAt="server" /> <asp:ListItem Text="MT" RunAt="server" /> <asp:ListItem Text="NC" RunAt="server" /> <asp:ListItem Text="ND" RunAt="server" /> <asp:ListItem Text="NE" RunAt="server" /> <asp:ListItem Text="NH" RunAt="server" /> <asp:ListItem Text="NJ" RunAt="server" /> <asp:ListItem Text="NM" RunAt="server" /> <asp:ListItem Text="NV" RunAt="server" /> <asp:ListItem Text="NY" RunAt="server" /> <asp:ListItem Text="OH" RunAt="server" /> <asp:ListItem Text="OK" RunAt="server" /> <asp:ListItem Text="OR" RunAt="server" /> <asp:ListItem Text="PA" RunAt="server" /> <asp:ListItem Text="RI" RunAt="server" /> <asp:ListItem Text="SC" RunAt="server" /> <asp:ListItem Text="SD" RunAt="server" /> <asp:ListItem Text="TN" RunAt="server" /> <asp:ListItem Text="TX" RunAt="server" /> <asp:ListItem Text="UT" RunAt="server" /> <asp:ListItem Text="VA" RunAt="server" /> <asp:ListItem Text="VT" RunAt="server" /> <asp:ListItem Text="WA" RunAt="server" /> <asp:ListItem Text="WI" RunAt="server" /> <asp:ListItem Text="WV" RunAt="server" /> <asp:ListItem Text="WY" RunAt="server" /> </asp:DropDownList> </td> <td> </td> </tr> <tr> <td> </td> <td> <fieldset> <legend>Scale</legend> <asp:RadioButtonList  RunAt="server" RepeatColumns="2" RepeatDirection="Horizontal"> <asp:ListItem Text="1 meter" RunAt="server" /> <asp:ListItem Text="2 meters" RunAt="server" /> <asp:ListItem Text="4 meters" RunAt="server" /> <asp:ListItem Text="8 meters" Selected="true" RunAt="server" /> <asp:ListItem Text="16 meters" RunAt="server" /> <asp:ListItem Text="32 meters" RunAt="server" /> </asp:RadioButtonList> </fieldset> </td> <td> </td> </tr> <tr> <td> </td> <td> <asp:Button Text="Show Image" OnClick="OnShowImage" Width="100%" RunAt="server" /> </td> <td> </td> </tr> </table> </form> <hr> <asp:Image  RunAt="server" /> </body> </html> <script language="C#" runat="server"> void OnShowImage (Object sender, EventArgs e) { StringBuilder builder = new StringBuilder (); builder.Append ("CityView.ashx?city="); builder.Append (City.Text); builder.Append ("&state="); builder.Append (State.SelectedItem.Text); builder.Append ("&scale="); switch (Scale.SelectedIndex) { case 0: builder.Append ("1"); break; case 1: builder.Append ("2"); break; case 2: builder.Append ("4"); break; case 3: builder.Append ("8"); break; case 4: builder.Append ("16"); break; case 5: builder.Append ("32"); break; } MyImage.ImageUrl = builder.ToString (); } </script>

Figure 11-12

CityView source code.

CityView.ashx

<%@ WebHandler Language="C#"  %> using System; using System.Web; using System.Drawing; using System.Drawing.Imaging; using System.IO; public class CityViewImageGen : IHttpHandler { public void ProcessRequest (HttpContext context) { // Extract user input from the query string string city = context.Request["City"]; string state = context.Request["State"]; string scale = context.Request["Scale"]; if (city != null && state != null) { // Determine the scale TS.Scale res = TS.Scale.Scale8m; if (scale!= null) { switch (scale) { case "1": res = TS.Scale.Scale1m; break; case "2": res = TS.Scale.Scale2m; break; case "4": res = TS.Scale.Scale4m; break; case "8": res = TS.Scale.Scale8m; break; case "16": res = TS.Scale.Scale16m; break; case "32": res = TS.Scale.Scale32m; break; } } // Generate the requested image string type = "image/jpeg"; ImageFormat format = ImageFormat.Jpeg; Bitmap bitmap = GetTiledImage (city, state, res, 600, 400); // If GetTiledImage failed, generate an error bitmap if (bitmap == null) { bitmap = GetErrorImage ("Image not available"); type = "image/gif"; format = ImageFormat.Gif; } // Set the response's content type context.Response.ContentType = type; // Write the image to the HTTP response bitmap.Save (context.Response.OutputStream, format); // Clean up and return bitmap.Dispose (); } } public bool IsReusable { get { return true; } } Bitmap GetTiledImage (string City, string State, TS.Scale Scale, int cx, int cy) { Bitmap bitmap = null; Graphics g = null; try { // Instantiate the TerraService proxy TS.TerraService ts = new TS.TerraService (); // Get the latitude and longitude of the requested city TS.Place place = new TS.Place (); place.City = City; place.State = State; place.Country = "USA"; TS.LonLatPt point = ts.ConvertPlaceToLonLatPt (place); // Compute the parameters for a bounding box TS.AreaBoundingBox abb = ts.GetAreaFromPt (point, TS.Theme.Photo, Scale, cx, cy); // Create an image to fit the bounding box bitmap = new Bitmap (cx, cy, PixelFormat.Format32bppRgb); g = Graphics.FromImage (bitmap); int x1 = abb.NorthWest.TileMeta.Id.X; int y1 = abb.NorthWest.TileMeta.Id.Y; int x2 = abb.NorthEast.TileMeta.Id.X; int y2 = abb.SouthWest.TileMeta.Id.Y; for (int x=x1; x<=x2; x++) { for (int y=y1; y>=y2; y--) { TS.TileId tid = abb.NorthWest.TileMeta.Id; tid.X = x; tid.Y = y; Image tile = Image.FromStream (new MemoryStream (ts.GetTile (tid))); g.DrawImage (tile, (x - x1) * tile.Width - (int) abb.NorthWest.Offset.XOffset, (y1 - y) * tile.Height - (int)abb.NorthWest.Offset.YOffset, tile.Width, tile.Height); tile.Dispose(); } } // Return the image return bitmap; } catch (Exception) { if (bitmap != null) bitmap.Dispose (); return null; } finally { if (g != null) g.Dispose (); } } Bitmap GetErrorImage (string message) { // Determine the width and height of the error message Bitmap bitmap = new Bitmap (1, 1, PixelFormat.Format32bppRgb); Graphics g = Graphics.FromImage (bitmap); Font font = new Font ("Verdana", 10); SizeF size = g.MeasureString (message, font); int cx = (int) size.Width; int cy = (int) size.Height; bitmap.Dispose (); g.Dispose (); // Generate a bitmap containing the error message bitmap = new Bitmap (cx, cy, PixelFormat.Format32bppRgb); g = Graphics.FromImage (bitmap); SolidBrush redBrush = new SolidBrush (Color.Red); SolidBrush whiteBrush = new SolidBrush (Color.White); g.FillRectangle (whiteBrush, 0, 0, 256, 64); g.DrawString (message, font, redBrush, 0, 0); whiteBrush.Dispose (); redBrush.Dispose (); font.Dispose (); g.Dispose (); // Return the image return bitmap; } }



Programming Microsoft  .NET
Applied MicrosoftNET Framework Programming in Microsoft Visual BasicNET
ISBN: B000MUD834
EAN: N/A
Year: 2002
Pages: 101

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net