Have you ever wanted to extract one piece of data from a web site for use in your Visual Basic application? No? Well let me tell you: It's called "screen scraping," and it's a pain in the neck. Most web sites with valuable content are designed by selfish people, programmers who think only about their own company's needs and nothing about other developers who need to pilfer essential data fromI mean, who need to add value to their own applications by enhancing it with content from a trusted third party.
Screen scraping is generally a bad thing. Not only is the HTML content ludicrously difficult to parse, but you never know when the web site owner is going to up and change the content without the courtesy of contacting you first. Fortunately, XML Web Services provides a solution to this problem. If a site has content or processes that need to be used by external applications, it can include a Web Service on the site that makes screen scraping unnecessary. XML Web Services implement the Web-based equivalent of function calls, complete with parameters and return values, all of which can be accessed remotely. They are based on published standards such as SOAP (Simple Object Access Protocol) that use plaintext and XML to simulate the function call between two systems.
There are a lot of technologies involved in making XML Web Services possible, but you don't really need to know them. Instead, you will build a standard Visual Basic method, mark it for use as a Web Service, and make it available on your web site.
Web services appear as .asmx files on your web site. In Visual Studio, you can either create a new web site and select "ASP.NET Web Service" as the project type, or add a "Web Service" item to an existing web site project. When you do, Visual Studio adds the necessary files to your project. The first is the actual .asmx file. It's a smart interface conduit between the web site and the actual web service code. Here's what I found in my WebService.asmx file.
<%@ WebService Language="VB" CodeBehind= "~/App_Code/WebService.vb" %>
This directive refers the caller to the WebService class in the associated WebService.vb source code file. That file is much more interesting.
Imports System.Web Imports System.Web.Services Imports System.Web.Services.Protocols <WebService(Namespace:="http://tempuri.org/")> _ <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ <Global.Microsoft.VisualBasic.CompilerServices. _ DesignerGenerated()> _ Public Class WebService Inherits System.Web.Services.WebService <WebMethod()> _ Public Function HelloWorld() As String Return "Hello World" End Function End Class
This code decorates the class and its methods with several attributes that mark those methods as Web Services. Remember that an attribute adds metadata to an assembly so that the compiler or some other program will do something special with the marked items. In this case, the <WebMethod> attribute tells ASP.NET to treat the HelloWorld function as a Web Service. ASP.NET responds by connecting all of the plumbing code that makes Web Services possible.
I'm going to replace the HelloWorld function with another one that at least pretends to do some real work.
<WebMethod()> _ Public Function NumberToText(ByVal sourceNumber _ As Integer) As String Select Case sourceNumber Case 0 : Return "Zero" Case 1 : Return "One" Case 2 : Return "Two" Case 3 : Return "Three" Case 4 : Return "Four" Case 5 : Return "Five" Case 6 : Return "Six" Case 7 : Return "Seven" Case 8 : Return "Eight" Case 9 : Return "Nine" Case Else : Return "Out of range" End Select End Function
The first attribute in the file refers to http://tempuri.org. You need to replace this with a namespace that is unique to your organization so that Web Services with the same name from different vendors don't conflict. Normally you put a URL for a web page that may or may not exist (it doesn't matter). As long as it's unique to your organization, you can put whatever you want. You can also change the name of the class if you wish, although you'll need to update the related .asmx file appropriately.
If you run this application in Visual Studio, your web browser opens with the page shown in Figure 22-10.
Figure 22-10. A web service running in your web browser
Web services are methods, and a web browser isn't a typical medium for running subroutines and functions, so the page in Figure 22-10 appears instead. Besides, the web service expects specially formatted XML content to run properly. If you click on the NumberToText link on the web page, it brings up a page from which you can test the service.
Web services are generally consumed by standard application code. Because I have this web service running on my system using my test ASP.NET web server, I'll write a desktop application to call the NumberToText method. Start a separate instance of Visual Studio and create a new Windows Forms project. Select the Project Add Web Reference menu command. The Add Web Reference form appears, a tool you use to locate local and remote web services. If you click on the Web services on the local machine link to find your custom web service, nothing will happen. Actually it will fail, because the test web server is not advertising the service. But you can specifically request the service if you know its address. To determine this, double-click on the ASP.NET Development Web Server icon in the system tray. The Root URL field will provide the base of the address. On my system at this particular moment, it says "http://localhost:1214/WebSite2," although it will change port numbers if I restart the service. Add to this the name of the .asmx file for your service, plus "?WSDL" as a query string.
Enter this address in the Add Web Reference form's URL field, and click Go. If successful, the web server responds with a WSDL (Web Service Description Language) XML file that provides the details of the web service. These details appear in the dialog as shown in Figure 22-11. Click the Add Reference button.
Figure 22-11. A recognized web service
Visual Studio automatically adds the reference to the My.WebServices object. To test out the service, I added a TextBox control and a Button control to Form1, and added the following code.
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click MsgBox(My.WebServices.WebService.NumberToText( _ CInt(Val(TextBox1.Text)))) End Sub
Running the program, typing in a number from zero to nine, and then clicking the button correctly calls the web service and returns the English version of the number. And it would have worked just as well if the NumberToText service were running on a web server at one of the research facilities at the South Pole.