Welcome to Web Service Secrets!
I’m Karl Moore and this is the twelfth and final installment of the .NET secrets series, the bundle of articles based on my latest book, VB.NET and ASP.NET Secrets.
Today, we’ll be exploring a bundle of Web service tips and samples to wire your applications, including:
- Five Things You Need to Do Before Publicizing Your Web Service
- Improving Performance with Easy Caching
- Adding Google Search to Your Programs
- View the Real World in Your Application, with TerraServer
Of course, these are only teasers—you’ll find full versions, plus hundreds more such tricks in the book. But you’ll need to cough up a few dollars first. Go on, don’t be mean.
Ready to begin exploring those nifty little Web service secrets? Top stuff…
Five Things You Need to Do Before Publicizing Your Web Service
So, you’ve written the greatest Web service since SlicedBread.asmx, and now you want to tell the whole world about your creation? Well, before you do, ensure you follow this list of five quick changes that will give your service that professional touch:
- Rename Your Class.
Nobody likes dealing with a Web service called Service1, so, before you redistribute, make sure that you rename your class from something like Public Class Service1 to something like Public Class Customer. Or something.
- Christen Your ASMX File.
You’ve renamed your Web service so it sounds all professional, but your clients are still accessing your Service via the http://localhost/Customer/Service1.asmx file. Eugh. To combat this, simple rename your ASMX file by right-clicking on it in the Solution Explorer and selecting Rename.
- Add a Service Description.
What does your Web service do? Provide access to your customer database or allow you to send SMS messages? Well, you could just let your clients guess. However, a more user-friendly technique would be to add a description to the <WebService> attribute. So, before distributing, change your class as follows:
<WebService(Description:="This class does amazing things _ with data.")> _ Public Class AmazingData ' ... etc ... End Class
This description is used in the automatically generated Web interface, plus is automatically absorbed by all clients using your service and utilized in the Visual Studio .NET programming environment.
- Add Method Descriptions.
Just as your service can include a description, so can your individual methods and functions. Again, this is used by the Web interface and Visual Studio .NET. And, again, it’s simple to implement: Just add a description to each <WebMethod> attribute, like so:
<WebMethod(Description:="Returns the current server date _ and time.")> _ Public Function GetServerDate() As Date Return Now End Function
- Change the Namespace.
You’ve already seen the .NET Framework organizing functionality into “namespaces.” They’re just unique identifiers for a certain set of functionality. That’s all a namespace is here, too: a unique string that identifies this Web service. By default, VS.NET uses http://www.tempuri.org/, and you will need to change this to a unique value. The namespace you provide doesn’t necessarily have to point to anything on the Web, but if it does, I’d recommended that you at least own the domain you use (ahem). So, change the namespace to something unique before unveiling your service by altering the Namespace property of the <WebService> attribute, as so:
<WebService(Description:="Yadda", _ Namespace:="http://www.amazingdata.com/query/")> _ Public Class AmazingData ' ... etc ... End Class
Improving Performance with Easy Caching
It’s a little-known fact, but you can actually “cache” what a Web service gives out and automatically serve up the same response next time, seriously speeding up popular, processor-intensive services.
How? Simply specify a CacheDuration parameter in the WebMethod attribute, like this:
<WebMethod(CacheDuration:=60)> _ Public Function GetWeather() As String ' ... complicated code ... End Function
Here, the Web server will cache and serve up the same results for GetWeather sixty seconds after the last query. You can check out this cute tip in action by returning the time from a function. See what happens?
Adding Google Search to Your Programs
It started off as “that nerdy site with the funny name” and ended up as the world’s number one search engine. Yes, it’s Google at www.google.com—an intelligent, easy-to-use searchable archive of over two billion Web pages.
And thanks to the world of Web services, you can plug your application into this mass of knowledge—with just a few lines of code.
How? First off, you’ll need to check out www.google.com/apis/ for information on the process. The main thing you’ll want to do here it create a Google account. You’ll be asked for your e-mail address and other details—in return, you’ll be provided with a license key. You need to use this when accessing the service.
Got your license key? Then fire up Visual Studio .NET and create a new project, such as a Windows application. Select Project > Add Web Reference and type in the URL of the Google .WSDL (Web Service Definition Language) file—http://api.google.com/GoogleSearch.wsdl as listed on the Google site—then press Return. Click ‘Add Reference’ when the button becomes available.
And now? Simply start using the service! To get you started, let’s review a little sample code. Here’s my own attempt at performing a simple search, returning a maximum of ten items for the term ‘Karl Moore’ (I know, narcissistic):
' Create a new Google search object Dim objSearch As New _ com.google.api.GoogleSearchService() ' Invoke the search method Dim objResults As _ com.google.api.GoogleSearchResult = _ objSearch.doGoogleSearch( _ "license-key-goes-here1Ga0szyTgT0K3r2Oq5pAMSvX1SYGvNYl", _ "Karl Moore", 0, 10, False, "", False, _ "", "", "") ' Loop through result elements Dim shtCount As Short For shtCount = 0 To objResults.endIndex - 1 MessageBox.Show(objResults.resultElements(shtCount).title & _ " - " & objResults.resultElements(shtCount).URL) Next
Top Tip: The Google service will include <b> bold tags around text that you search for. This doesn’t matter if you’re developing for Web applications, where highlighting searched-for terms is actually quite user friendly. For Windows applications, however, that don’t use HTML tags, you’ll want to strip these out using a custom algorithm or regular expression (check out my “Converting HTML to Text, Easily” tip in the “More .NET Secrets” chapter of my book, VB.NET and ASP.NET Secrets for a ready-to-run algorithm).
So, that’s a regular search. But there’s more. Regular users of Google will know that when you accidentally mistype a search term, the engine will suggest a possible correct spelling. You can access that exact functionality through your Web service too, as so:
' Create a new Google search object Dim objSearch As New _ com.google.api.GoogleSearchService() ' Retrieve the suggest spelling, if any Dim strSuggestion As String strSuggestion = objSearch.doSpellingSuggestion( _ "license-key-goes-here1Ga0szyTgT0K3r2Oq5pAMSvX1SYGvNYl", _ "Britnee Speyers") MessageBox.Show(strSuggestion)
Thought that was it? You also can retrieve cached versions of a page (alongside the Google “this is a cached page, click here for the latest version, etc.” HTML). Here’s a little sample code:
' Create a new Google search object Dim objSearch As New _ com.google.api.GoogleSearchService() ' Retrieve cached version of a page Dim bytPage() As Byte = _ objSearch.doGetCachedPage( _ "license-key-goes-here1Ga0szyTgT0K3r2Oq5pAMSvX1SYGvNYl", _ "www.karlmoore.com") ' Convert base 64 byte array to string Dim strHTML As String = _ System.Text.ASCIIEncoding.ASCII.GetString(bytPage) MessageBox.Show(strHTML)
Here, I’ve simply demonstrated the three core features of the Web service; however, by downloading the Developer’s Toolkit above, you can really delve into any of these areas. By filling out a few of the extra . doGoogleSearch parameters, for example, you can restrict results to a particular language, search within a particular topic, or alter the number of returned results. Be sure to check it out.
Also, it’s worthwhile noting that at the time of writing, the Google Web service was still in beta. It is, however, unlikely that Google will change the interface definitions (a prediction based on the way it has continued to keep certain redundant properties available, even though still in beta—a sure sign of a user-conscious organization, if not one lacking in a little foresight). In addition, be aware that (again at the time of writing) you are limited to 1,000 searches per day, per license key and that no commercial pay-per-search facility is yet available.
Plugging directly into the power that is Google, through Web services
View the Real World in Your Application, with TerraServer
The Statue of Liberty. Yankee Stadium. The Pentagon. Hoover Dam. Unrelated? I think not. You see, they’re all listed in TerraServer, the mass Microsoft-supported Web service that allows you to view the world and all (or at least most/some) of its famous sights from the skies.
You can check out the Web version of this cool service at terraserver.microsoft.com—or you can use the power of Web services to plug straight into this functionality.
In this example, I’m going to show you how to connect into the service, then retrieve an image using its “popular name”—such as ‘White House’ or ‘Statue of Liberty.’ You can do much more, certainly; however, this example will at least demonstrate some of the capabilities—and perhaps make you aware as to how troublesome the graphic ‘crunching’ code can get.
Ready to go? Launch Visual Studio .NET and create a new application. Select Project > Add Web Reference from the menu and type in the URL of the TerraServer description page>http://terraservice.net/TerraService.asmx>then press Return. Click the ‘Add Reference’ button when available.
Next, add an Imports statement to save us constantly referring to the net.terraservice namespace. If you’re creating this in a Windows form project, you’ll need to type something like the following just above the Public Class part of your form code:
Now, we’re ready to start writing code to use our service. Add the following method to your formclass (or class, or whatever):
Public Sub CreateBitmapFromPlaceName( _ ByVal PlaceName As String, ByVal FileName As String) ' Size of image to create Const WIDTH As Integer = 600 Const HEIGHT As Integer = 400 ' Set up objects to use Dim objTheme As New Theme() Dim objScale As New Scale() Dim objTS As New TerraService() Dim objABB As AreaBoundingBox Dim imgImage As Image Dim objPF() As PlaceFacts Try ' Retrieve list of matching points objPF = objTS.GetPlaceList(PlaceName, 1, False) ' If no matches, exit If objPF.Length = 0 Then Exit Sub ' Settings - type of image and scale objTheme = Theme.Photo objScale = objScale.Scale2m ' Gets details of the final full image AreaBoundingBox objABB = objTS.GetAreaFromPt(objPF(0).Center, _ objTheme, objScale, WIDTH, HEIGHT) ' Create objects to handle image in memory Dim objPFmt As System.Drawing.Imaging.PixelFormat = _ System.Drawing.Imaging.PixelFormat.Format32bppRgb Dim imgTemp As Image = New Bitmap(WIDTH, HEIGHT, objPFmt) Dim objGraphics As Graphics = Graphics.FromImage(imgTemp) ' Create objects to store current locations Dim intStartX As Integer = objABB.NorthWest.TileMeta.Id.X Dim intStartY As Integer = objABB.NorthWest.TileMeta.Id.Y Dim x, y As Integer ' Cycle through the portions of our whole AreaBoundingBox, ' incrementally retrieving and stiching together our image For x = intStartX To objABB.NorthEast.TileMeta.Id.X For y = intStartY To objABB.SouthWest.TileMeta.Id.Y _ Step -1 Dim objTID As TileId Dim imgTile As Image objTID = objABB.NorthWest.TileMeta.Id objTID.X = x objTID.Y = y imgTile = Image.FromStream(New System.IO. _ MemoryStream ( _ objTS.GetTile(objTID))) objGraphics.DrawImage(imgTile, _ (x - intStartX) * imgTile.Width - _ objABB.NorthWest.Offset.XOffset, _ (intStartY - y) * imgTile.Height - _ objABB.NorthWest.Offset.YOffset, _ imgTile.Width, imgTile.Height) Next Next ' Finally, save to the passed filename imgTemp.Save(FileName, System.Drawing.Imaging. _ ImageFormat.Bmp) Catch Return End Try End Sub
Well, this is a pretty hefty piece of code. Let me walk you through it. We begin by defining the dimensions of the width and height of the image you want, then declare a few objects we’ll be using later on. Next, we retrieve a list of PlaceFacts objects, depending on the place name passed into the method, exiting if we have no matches. After that, we initialize a couple of settings—the type of image and the scale. Moving on, the next line takes a WIDTH by HEIGHT area around the center of the first matching PlaceFacts object, creating an AreaBoundingBox object—which essentially defines the area for your image.
Continuing, our code then creates various objects to handle our image, then begins one big loop. Starting at the upper left (northwest) point, it goes about chunk by chunk, retrieving an array of bytes from the Web service representing an image block (it has to move in this block format because the service only returns images to a maximum of 200 x 200 at any one time). As one loop moves across, collecting images, the second one moves down—and eventually the whole image is stitched together. Finally, our Graphic object is saved to the specified filename as a bitmap—ready to perhaps load into a control or stream through a Web page.
We can call this function a little like this:
CreateBitmapFromPlaceName("Statue of Liberty", "c:myimage.bmp")
And that’s it—one simple line of code, yes, but a disproportionate number of hours spent figuring how to make it work. However, that’s still not all the TerraServer can do—it may be the most popular usage, but there’s always more to discover. Did you know you can retrieve the population of an area you’ve mapped, for example—or convert a longitude and latitude value to the nearest place name on file?
Check out terraserver.microsoft.com and click the ‘Web services’ link for documentation and examples. Good luck and enjoy the service!
Spy on the Pentagon with the Terraserver Web service
Well, that’s a rap, folks!
You’ve been reading Karl Moore with the .NET secrets series. I do hope our paths meet again shortly. Don’t forget to stop by www.karlmoore.com to read the latest, or drop me a personal note at [email protected].
Thanks again and bye for now!