WebServices,Clients,andProxies You have seen that a Web service uses SOAP to provide a mechanism for receiving requests and sending back results. SOAP uses XML to format the data being transmitted, which rides on top of the HTTP protocol used by Web servers and browsers. This is what makes Web services so powerful—HTTP and XML are well understood (in theory anyway) and are the subjects of several standards committees. SOAP itself is going through the standardization process and has been adopted by most companies that want to make their services available over the Web. A client that “talks” SOAP can communicate with a Web service. The client and the Web service can be implemented in totally different languages, running on otherwise incompatible systems. For example, a Microsoft Visual Basic client running on a handheld device can communicate with a Web service being hosted on an IBM 390 mainframe running UNIX. So how does a client “talk” SOAP? There are two ways: the difficult way and the easy way. Talking SOAP: The Difficult Way In the difficult way, the client application must perform a number of steps: 1. Determine the URL of the Web service running the Web method. 2. Perform a Web Services Description Language (WSDL) inquiry using the URL to obtain a description of the Web methods available, the parameters used, and the values returned. This is an XML document. (You saw an example in the previous chapter.) 3. Convert each Web method call into the appropriate URL and serialize each parameter into the format described by the WSDL document. 4. Submit the request, along with the serialized data, to the URL using HTTP. 5. Wait for the Web service to reply. 6. Using the formats specified by the WSDL document, de-serialize the data returned by the Web service into meaningful values that your application can then process. This is a lot of work to just invoke a method, and it is potentially error-prone. Talking SOAP: The Easy Way The bad news is that the easy way to use SOAP is not much different from the difficult way. The good news is that the process can be automated because it is largely mechanical. Many vendors supply tools that can generate proxy classes based on a WSDL description. The proxy hides the complexity of using SOAP and exposes a simple programmatic interface based on the methods published by the Web service. The client application calls Web methods by invoking methods with the same name in the proxy. The proxy converts these local method calls into SOAP requests and sends them to the Web service. The proxy waits for the reply, de-serializes the data, and then passes it back to the client just like the return from any simple method call. Consuming the ProductService Web Service You have created a Web service call that exposes two Web methods: GetProductInfo to return the details of a specified product, and HowMuchWillItCost to determine the cost of buying n items of product x from Northwind Traders. In the following exercises, you will use this Web service and create an application that consumes these methods. You'll start with the Get- ProductInfo method. Create a Web service client application 1. Start another instance of Visual Studio 2005. This is important. The ASP.NET Development server stops if you close the NorthwindServices Web service project, meaning that you won't be able to access it from the client (an alternative approach you can use is to create the client application as a project in the same solution as the Web service). When you host a Web service in a production environment by using IIS, this problem does not arise because IIS runs independently from Visual Studio 2005. 2. In the second instance of Microsoft Visual Studio 2005, create a new project using the Windows Application template. Name the project ProductInfo and save it in the \Microsoft Press\Visual CSharp Step By Step\Chapter 28 folder in your My Documents folder. 3. Change the filename of the Form1.cs file to ProductForm.cs. 4. Change the size of the form to 392, 400. Set its Text property to Product Details. 5. Add 10 labels to the form, evenly spaced down the left side. From top to bottom, set the Text property of each label using the following values: Product Name, Product ID, Supplier ID, Category ID, Quantity Per Unit, Unit Price, Units In Stock, Units On Order, Reorder Level, and Discontinued. 6. Add nine text boxes to the form adjacent to the first nine labels. Clear the Text property for each text box. Set the Name property of each text box from top to bottom using the following values: productName, productID, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, and reorderLevel. 7. Add a check box to the form next to the Discontinued label and below the reorderLevel text box. Set its Name property to discontinued, and then clear its Text property. 8. Add a button to the form, to the right of the productName text box. Change the name of the button to getProduct, and then set its Text property to Get Product. The completed form should look like the following graphic: Add a reference to the Web service 1. On the Project menu, click Add Web Reference. The Add Web Reference dialog box opens. This dialog box allows you to browse for Web services and examine the WSDL descriptions. 2. Type the URL of the NorthwindServices Web service in the Address text box at the top of the dialog box: http://localhost:4500/NorthwindServices/Service.asmx. Click Go. TIP If the Web service is hosted by IIS on your computer, you can click the “Web services on the local machine” hyperlink in the left pane of the dialog box rather than typing the address in manually. In our case, the Web service is hosted by the ASP.NET Development server and won't appear if you click this hyperlink. The Web service test page displaying the GetProductInfo and HowMuchWillItCost methods appears. Change the value in the Web reference name text box to NorthwindServices, as shown in the following graphic: 3. Click Add Reference. Look at the Solution Explorer. A new folder called Web References is added that contains an item called NorthwindServices. Click the NorthwindServices Web reference and examine its properties in the Properties window. You will notice the Web Reference URL property, which contains the URL of the Web service. Execute a Web method 1. Display ProductForm.cs in the Code and Text Editor window. Add the following using statement to the list at the top of the file: using ProductInfo.NorthwindServices; When you add a Web reference to a project, the proxy generated by the Web service is placed in a namespace that is named after the Web service reference—in this case, NorthwindServices. 2. Create an event method for the Click event of the getProduct button called getProduct_Click. In the getProduct_Click method, create the following variable: Service northwindService = new Service(); Service is the proxy class that provides access to the Web service (the proxy will always be named after the Web service). It resides in the NorthwindServices namespace. To use the Web service, you must create an instance of the proxy, which is what this code does. 3. Add code to execute the GetProductInfo Web method to the getProduct_Click method. You are probably aware of how unpredictable networks are, and this applies doubly to the Internet. Create a try/catch block below the statement that creates the northwind Service variable. Remember that the Web service will also throw an exception if you try to access a non-existent product. 4. try 5. { 6. // Code goes here in the next steps 7. } 8. catch (Exception ex) 9. { 10. MessageBox.Show("Error fetching product details: " + 11. ex.Message, "Error", MessageBoxButtons.OK, 12. MessageBoxIcon.Error); } Add the following statement to the try block: Product prod = northwindService.GetProductInfo(productName.Text); The proxy object (northwindService) makes the call to the GetProductInfo Web method look like an ordinary local method call. The information returned by the GetProductInfo method is assembled into an instance of the Product class. The WSDL description of the Web service provides enough information to define the structure of this class, and you can use it in your client application as shown here. 13. Add the following statements, which extract the details from the Product object and display them on the form, to the try block: 14. productID.Text = prod.ProductID.ToString(); 15. supplierID.Text = prod.SupplierID.ToString(); 16. categoryID.Text = prod.CategoryID.ToString(); 17. quantityPerUnit.Text = prod.QuantityPerUnit; 18. unitPrice.Text = prod.UnitPrice.ToString(); 19. unitsInStock.Text = prod.UnitsInStock.ToString(); 20. unitsOnOrder.Text = prod.UnitsOnOrder.ToString(); 21. reorderLevel.Text = prod.ReorderLevel.ToString(); discontinued.Checked = prod.Discontinued; Test the application 1. Build and run the project. When the Product Details form appears, type Aniseed Syrup in the Product Name text box and click Get Product. After a short delay while the client instantiates the proxy, the proxy marshals the parameter and sends the request to the Web service. The Web service reads the database, creates a Product object, marshals it as XML, and then sends it back to the proxy. The proxy unmarshals the XML data and creates a copy of the Product object, and then passes this copy to your code in the getButtonClick method. The details for Aniseed Syrup then appear in the form as shown by the following graphic: 2. Type Tofu in the Product Name text box, and then click Get Product. You will probably find that the details are displayed more quickly this time. 3. Type Sticky Toffee in the Product Name text box, and then click Get once more. Because this product does not exist, the Web service will throw an exception that is passed back to your application. If you look closely, you will see the “No such product Sticky Toffee” message. 4. Click OK to acknowledge the error. Close the Product Details form and return to the Visual Studio 2005 programming environment. WebServices, Anonymous Access, and Authentication When you create a Web service client using Visual Studio 2005, the client application executes Web services using anonymous access by default. This might be fine when building and testing Web services in a development environment using the ASP.NET Development Web server, but in a production environment using IIS you might want to restrict access to authenticated clients only. You can configure the authentication mechanism for a Web service hosted by IIS using the Internet Information Services console, available from the Administrative Tools folder in the Control Panel. If you expand the Default Web Site node, select your Web service, and click Properties from the Action menu, you can change the Directory Security settings by clicking the Edit button under Anonymous Access And Authentication Control. Make sure the Anonymous Access box is checked to permit unauthenticated access—the accepted convention is to use the local IUSR account for such access; the Web service will execute using this identity, which must be granted access to any resources used by the Web service, such as a SQL Server database. The alternative to using anonymous access is using authenticated access. If you clear the Anonymous access check box and select one or more of the authenticated mechanisms (Digest, Basic, Integrated Windows), you can restrict access to clients that supply a valid user name and password. For more information on the differences between the authenticated access modes, consult the Internet Information Services documentation (click Help in the Authentication Methods dialog box). You can supply the information needed to authenticate the client application by setting the Credentials property of the Web service proxy at run time. This property is a NetworkCredential object (the NetworkCredential class is located in the System.Net namespace). The following code creates a NetworkCredential object for the user “John,” with the password “JohnsPassword” and sets the Credentials property of the productService Web service proxy: using System.Net; … private void getProduct_Click( .) { Service northwindService = new Service(); try { NetworkCredential credentials = new NetworkCredential("John", "JohnsPassword"); productService.Credentials = credentials; Product prod = productService.GetProductInfo( .); … } … } The user name and password must be valid for the Windows domain (a different Windows domain can be specified as an optional third parameter to the NetworkCredential constructor), and the specified account must be granted access to the various resources used by the Web service if it is to function correctly. . Web Services, Clients, and Proxies You have seen that a Web service uses SOAP to provide a mechanism for receiving requests and sending back. protocol used by Web servers and browsers. This is what makes Web services so powerful—HTTP and XML are well understood (in theory anyway) and are the subjects