As a .NET programmer, you've probably already heard more than a little about Microsoft's favorite new innovation, the hotly hyped web services. Web services play much the same role as components exposed through Remoting: They're packages for business code that you want to execute on another computer. Unlike Remoting, web services use the ASP.NET engine, require IIS, and stress interoperability with other platforms through open standards such as SOAP, which is used to communicate with a web service, and Web Services Description Language (WSDL), which is used to describe the functionality provided by a web service.
Here's a short list of the key differences between Microsoft's two new distributed technologies, Remoting and web services:
Remoting has the option of using faster communication through TCP/IP connections and the BinaryFormatter. Web services only support SOAP message formatting, which uses larger XML text messages.
Web services support open standards that target cross-platform use, such as SOAP and WSDL. This allows third-party clients (such as a Java application) to interact with them.
Web services only support a small set of .NET types for parameters or return values. You can use your own custom classes, but they can only include data members. Property procedures, constructor logic, methods, and so on, cannot be used.
Web services don't require a component host application. Instead, this functionality is provided by the ASP.NET engine and IIS.
Web services are requested much like a web page over an HTTP channel. This allows web-service requests to cross most firewalls. Of course, the same is possible with Remoting, as long as you configure your component accordingly.
Web services are always stateless. That means they can't run asynchronously in the background or perform tasks continuously. Instead, they're created to serve a single client request and are destroyed immediately when the request ends. Remoting components don't have this limitation, as long as they're client-activated or Singleton objects (such as the Talk .NET coordination server in Chapter 4).
It's sometime said that Remoting always performs better than web services, because it can use binary formatting and the TCP/IP protocol, rather than larger SOAP messages and the HTTP protocol. This is true to a point, but this minor advantage can be countered by some of the built-in ASP.NET services, such as caching. It's also true that the restricted nature of web services simplifies design issues. It's generally easier to create a high-performance stateless object such as a web service than a stateful coordination object that needs to make heavy use of threads and synchronization codes.
Most .NET programmers have already heard more than enough about the promise of .NET web services. In this chapter, we'll cover the most important essentials in an abbreviated form, so that we can get back to peer-to-peer programming as quickly as possible. You won't learn about background information such as the SOAP and WSDL standards. If you're interested in a more detailed exploration of web services, there are many excellent books available. And if you've already mastered web services, feel free to skip ahead.
The ASP.NET engine handles a web-service request in much the same way as aweb-page request. The only difference is that web-service results are usually formatted in an XML grammar called SOAP, not ordinary HTML.
Here's an overview of the process (shown in Figure 8-3):
A client sends a SOAP-formatted request to a web service.
IIS receives the request, determines that it's for ASP.NET, and invokes the ASP.NET engine.
ASP.NET creates the web-services object.
ASP.NET runs the requested method with the supplied information.
ASP.NET destroys the web-services object.
ASP.NET returns the web-services result in a SOAP-formatted message over HTTP.
ASP.NET uses a pool of worker threads to handle multiple concurrent requests efficiently. A new, distinct web-service object is created for each request, ensuring that you don't need to worry about creating your own custom threading code.
IIS is the software a computer needs to serve web requests, whether they're for ordinary HTML pages or ASP.NET web pages and web services. IIS performs two key functions:
It exposes directories on your hard drive as virtual web directories over HTTP. For example, you might map the path C:\MyWeb to http://[ComputerName]/PublicWeb. Now, the web services and web pages in C:\MyWeb can be accessed through HTTP in a web browser, using addresses that start with http://[ComputerName]/PublicWeb.
Using file extensions, IIS maps web requests to the application that can handle them. For example, ASP.NET pages (.aspx files) and web services (.asmx files) are registered to the ASP.NET worker process. When IIS receives a web request for one of these file types, it invokes the ASP.NET engine, which handles the rest of the work.
IIS also imposes its own security controls, which you can customize. For example, by default, IIS will not allow a client to browse the list of files contained in a virtual directory. You can also use IIS to authenticate the user by demanding Windows authentication credentials, although this technique is of little use in a peer-to-peer application because the clients won't have Windows user accounts on the server.
IIS is included with the Windows 2000, Windows XP, and Windows Server 2003 operating systems, but isn't automatically installed. To install it, follow these steps:
Choose Add or Remove Programs, and click Add/Remove Windows Components.
Find Internet Information Server in the list, select it, and click Next to install the appropriate files.
You can test if IIS is installed by requesting the page http://localhost/localstart.asp in your web browser. Localstart.asp is an ordinary ASP file that's stored in the root directory of your computer's website. Localhost is an alias that always refers to the IP address 127.0.0.1. This is known as the loopback address, because it always refers to the current computer. If your request works and you see the IIS Help page in your browser, IIS is installed correctly.
Typically, the root website http://localhost is mapped to the directory c:\intepub\wwwroot. You can create new virtual directories using the IIS Manager administrative utility. Just select Internet Information Server from the Administrative Tools section of the Control Panel, and follow these steps:
Right-click the Default Web Site item (under your computer in the tree), and choose New Virtual Directory to start the Virtual Directory wizard. Click Next.
Enter the alias, which is the name of the new virtual directory you want to create, and click Next.
Choose the physical directory that will be exposed. Click Next to continue.
The next window allows you to adjust the permissions granted to the virtual directory. The default settings allow clients to run ASP.NET pages and web services, but they can't make any modifications or upload files. This is the recommended configuration.
Click Next, and then Finish to end the wizard. You will see the virtual directory appear in the IIS Manager tree.
It's always a good idea to create a dedicated virtual directory before creating a project in Visual Studio .NET. Otherwise, your project will automatically be placed in a subdirectory of c:\inetpub\wwwroot. The discovery service presented in this chapter uses the virtual directory http://[ComputerName]/Discovery, which is mapped to the physical directory C:\Code\P2P\Chapter08\Discovery.
Any computer on your network can access a web service using the computer name or IP address of the computer where the web service is hosted. However, if you want to expose a web service on the Internet, you'll probably need to invest in a fixed IP address or enlist the services of a dedicated Internet hosting company.With a fixed IP address, it also becomes possible to register a domain name (for example, http://www.mysite.com).
Like a Remoting component, a web service is, at its simplest, just a collection of methods organized in a class. To expose a method over the Internet, you need to add a <WebMethod> attribute to the method. In addition, it's a common convention to derive from the WebService class, although this isn't required. Both the WebMethod attribute and the WebService class are found in the System.Web.Services namespace.
Here's a sample web service with one method:
Public Class MyService <WebMethod()> _ Public Sub MyMethod() ' (Code goes here.) End Sub End Class
Although web services can include any .NET code, they only support a limited set of .NET types for use as method parameters or return values. Supported types include
Basic data types such as integers, floating point numbers, Boolean variables, dates and times, strings, and enumerations.
Arrays of any supported type.
The ADO.NET DataSet (although this type will probably not be understood by non-.NET clients).
The XmlNode object, which represents an arbitrary portion of an XML document.
A custom class or structure. However, only data members will be preserved. All code will be ignored.
There's one nice side to this limitation. It means that you never need to distribute a custom assembly to clients that need to use a web service. Instead, they can download all the information they need about the service.
Remember, all web services are stateless. That means that if you create any member variables, they'll be initialized to default empty values every time a web method is invoked. Similarly, if you create a constructor, it will be called before every method call.
In order to deploy a web service on a website, you need to follow three simple steps:
Compile the web service into a .dll assembly.
Copy the assembly into the bin directory of a virtual directory on your server.
Add an .asmx file extension that will allow you to identify the web service in the virtual directory.
The .asmx file is the web-service endpoint. The client cannot access your web-service .dll directly—instead, it makes a request for the .asmx file, along with information about the method it wants to invoke and the data it's sending. The .asmx file simply indicates the class and assembly name for the corresponding web service in a single line of text:
<%@ WebService Language="vb" Class="MyService" %>
The ASP.NET engine will then instantiate the corresponding class from the bin subdirectory and run the requested method.
Visual Studio .NET automates this process when you create a web-service project, compiling the web service into an assembly and generating the corresponding .asmx file. These are the only two files you need to deploy.
As with Remoting, a web-service client communicates with a web service using a proxy. With Remoting, the proxy is generated dynamically at runtime. With web services, the proxy is generated by some tool at design time. In Visual Studio .NET, the proxy is created in a process called "adding a web reference." It's at this point that you specify the location of the web service, and then Visual Studio .NET generates a proxy class that can communicate with it and adds the proxy class to your project.
The proxy class has the same interface as the web service it communicates with. To use a web method, you create an instance of the proxy class and invoke the method of the proxy class. To your code, it seems like using an ordinary local object, but behind the scenes the proxy class creates and sends a SOAP request, waits for a response, and converts the return value into the expected .NET type. If you haven't already used web-service references in your own projects, you'll see how to add one in the next chapter.
Now that we've covered the groundwork, we're ready to begin coding a real-world application. The next section begins by creating a registration database, which we'll expose through a simple .NET web service.