Building a Web Service

Getting started with Web services is easy if you use C#Builder's built-in wizards. Because Web services use ASP.NET technology (one reason why they are sometimes called ASP.NET Web Services), the project setup is the same.

To run the Web Service Wizard, start a new Project Group if one hasn't been created yet. Select File, New, Other to get the New Item dialog to appear. Under the C# ASP Project folder, start the ASP.NET Web Service Application Wizard. You could have also added a Web service to an existing Project Group by selecting Add New Project from the Project Group context menu and then selecting ASP.NET Web Service Application under the C# ASP Project folder. Enter a name in the New ASP.NET Application dialog (see Figure 17.1) that appears. The Location defaults to the IIS default directory, but you may want to change this to a local directory where the rest of the projects in the project group are. To permanently change the default location, select Tools, Options, ASP.NET Options and enter a new path into Base Directory. The Server option enables selection of IIS, Cassini, or Not Specified. The Cassini Web Server is a free, open source Web server written by Microsoft. Its source code can be found under the C#Builder examples directory (C:\Program Files\Borland\BDS\1.0\ Examples\C#\Cassini on my system) or downloaded from the ASP.NET Community Site at http://www.asp.net. The View Server Options button toggles to a Hide Server Options button and displays options that are specific to the selected Server option. The wizard will create a new Web Service project when you click the OK button.

Figure 17.1. The New ASP.NET Application dialog for creating a Web service.

graphics/17fig01.jpg

When the wizard creates a new project, it adds several files to the project and opens the main Web Service file in the designer. The first file worth mentioning is WebService1.asmx or whatever was entered into the Name field in the New ASP.NET Application dialog plus the .asmx file extension. For the example in this section, the file is named DataService.asmx. The file extension .asmx distinguishes Web Services from ASP.NET Web Forms, which have an .aspx file extension. The other files, AssemblyInfo.cs, Global.asax, and web.config, perform the same function as for ASP.NET Web Form projects, as was discussed in Chapter 11, "Introduction to ASP.NET."

The DataService.asmx file will appear in the designer surface when the project is created. The Web Service designer surface looks like the ASP.NET Web Forms designer surface, but it isn't meant for visual controls. If a visual control is dropped on the surface, its small icon representation appears and an instance of its type is added to the code-behind. Most of the time, there is no practical reason to add a visual component because no one will see it. Instead, the Web Service designer surface is well suited for nonvisual components, such as BDP data components, which will be used in this example.

In addition to the designer surface editor, the DataService.asmx file has an HTML editor and a code editor. Similar to the designer surface editor, the HTML editor doesn't render a visual appearance. In fact, any HTML on this page will return the error CS0116: A namespace does not directly contain members such as fields or methods if the Web service is called. For visual Web applications, it will be necessary to create an ASP.NET Web Form. The primary purpose of the HTML editor file is to hold the WebService directive (see Listing 17.1).

Listing 17.1 The WebService Directive (DataService.asmx)
 <%@ WebService    Language="C#"    Debug="true"    Codebehind="DataService.asmx.cs"     %> 

Table 17.1 contains more information on WebService directive attributes. Remember to set Debug to false if you don't want to generate debug symbols for a release build. Also, if the error Could not create type 'DataServiceDemo.DataService' appears when you run a program, it means that either the namespace or class name in the code-behind file does not match the Class attribute on the WebService directive. Try it by changing the name of the Class attribute (for example, DataServiceDemo.DataService1).

Table 17.1. WebService Directive Attributes

ATTRIBUTE NAME

PURPOSE

Class

Identifies the class that implements the Web service.

CodeBehind

Used by C#Builder to find the code-behind file that implements the Web service.

Debug

Compile with debug symbols if set to true.

Language

Language used for inline code.

The code-behind file (see Listing 17.2) contains the actual implementation of the Web service. When the wizard runs, it creates two sample Web methods, which are trivial to uncomment and run. The example in this section goes a step further and performs a database access to return a DataSet of the Products table from the Northwind database. See Chapter 15, "ADO.NET and File I/O," on how to set up a database using BDP components. The difference in the way this example is set up is that it does not implement the BdpCommandBuilder. Instead, it provides services that perform INSERT, UPDATE, and DELETE operations on selected records. Figure 17.2 shows the BdpConnection and BdpDataAdapter that have been dragged to the designer surface and the DataSet, which was generated by the BdpDataAdapter Configuration editor.

Figure 17.2. BDP components on the Web Service designer surface.

graphics/17fig02.jpg

The code for this Web service (see Listing 17.2) includes an InitializeComponent section, which includes all the automatically generated code created by C#Builder when the BDP components were dragged-and-dropped onto the designer surface. Below that are four database access routines, manually added for this example: GetProducts, InsertProduct, UpdateProduct, and DeleteProduct.

Listing 17.2 Web Service Implementation in a Code-Behind File (DataService.asmx.cs)
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; using Borland.Data.Provider; namespace DataServiceDemo {    [WebService(       Name="ProductsTableService",       Namespace="http://www.samspublishing.com/",       Description="Performs Products tablecommands.")]    public class DataService: System.Web.Services.WebService    {       public DataService()       {          InitializeComponent();       }       #region Web Form Designer generated code       //Required by the Web Services Designer       private IContainer components = null;       /// <summary>       /// Required method for Designer support - do not modify       /// the contents of this method with the code editor.       /// </summary>       private void InitializeComponent()       {          // auto-generated code removed for clarity       }       /// <summary>       /// Clean up any resources being used.       /// </summary>       protected override void Dispose( bool disposing )       {          if(disposing && components != null)          {             components.Dispose();          }          base.Dispose(disposing);       }       #endregion       private System.Data.DataTable Table1;       private System.Data.DataColumn dataColumn1;       private System.Data.DataColumn dataColumn2;       private System.Data.DataColumn dataColumn3;       private Borland.Data.Provider.BdpConnection conn;       private Borland.Data.Provider.BdpDataAdapter productsDA;       private Borland.Data.Provider.BdpCommand bdpSelectCommand1;       private Borland.Data.Provider.BdpCommand bdpInsertCommand1;       private Borland.Data.Provider.BdpCommand bdpUpdateCommand1;       private Borland.Data.Provider.BdpCommand bdpDeleteCommand1;       private System.Data.DataSet productsDS;       [WebMethod(Description="Returns data from Product table.")]       public DataSet GetProducts()       {          return productsDS;       }       // executes an insert, update or delete       protected void PerformNonQuery(string nonQueryString)       {          BdpCommand nonQueryCommand = new BdpCommand(nonQueryString, conn);          try          {             conn.Open();             nonQueryCommand.ExecuteNonQuery();          }          catch          {             throw;          }          finally          {             if (conn != null)             {                conn.Close();             }          }       }       [WebMethod(Description="Adds a new product.")]       public void InsertProduct(          string productName,          string quantityPerUnit,          float unitPrice)       {          string insertString = String.Format(          @"insert into Products            (ProductName, QuantityPerUnit, UnitPrice)            values ('{0}', '{1}', {2})",          productName, quantityPerUnit, unitPrice);          PerformNonQuery(insertString);       }       [WebMethod(Description="Modifies an existing product.")]       public void UpdateProduct(          string newProductName,          string newQuantityPerUnit,          float newUnitPrice,          string oldProductName,          string oldQuantityPerUnit,          float oldUnitPrice)       {          string updateString = String.Format(          @"UPDATE Products            SET    ProductName     = '{0}',                   QuantityPerUnit = '{1}',                   UnitPrice       =  {2}            WHERE  ProductName     = '{3}'            and    QuantityPerUnit = '{4}'            and    UnitPrice       =  {5}",          newProductName, newQuantityPerUnit, newUnitPrice,          oldProductName, oldQuantityPerUnit, oldUnitPrice);          PerformNonQuery(updateString);       }       [WebMethod(Description="Removes a product.")]       public void DeleteProduct(          string productName,          string quantityPerUnit,          float unitPrice)       {          string deleteString = String.Format(          @"delete from Products            where  ProductName     = '{0}'            and    QuantityPerUnit = '{1}'            and    UnitPrice       =  {2}",          productName, quantityPerUnit, unitPrice);          PerformNonQuery(deleteString);       }    } } 

There is an attribute, WebMethod, being used on the methods in Listing 17.2 that identifies a method as being an available service for callers. Without the WebMethod attribute, a method is not visible to clients using Web Service protocols (SOAP, WSDL, HTTP, and so on).

Because this Web service inherits System.Web.Services.WebService, it has access to common ASP.NET objects, such as Application, Session (only if sessions are enabled as will be discussed later), Server, and User. Although this is a Web service, it is still a C# class and can otherwise be used like any other class. For example, another class may inherit this one and implement its own methods in addition to the ones in DataService. That would enable the derived class to expose its own methods and DataService methods to callers. The next section goes into detail on the WebMethod attribute and explains another attribute called WebService.

Because the productsDS DataSet in Listing 17.2 is already instantiated and populated by the call to InitializeComponent in the Web Service constructor, it is available for use. Therefore, the GetProducts Web service simply returns productsDS.

The InsertProduct, UpdateProduct, and DeleteProduct methods have much the same logic, except for their query strings, which are standard SQL. Each calls the PerformNonQuery method to invoke an ExecuteNonQuery method. The BdpCommand object may also be used to call ExecuteReader, which returns a DataReader, or ExecuteScalar, which is designed to return a single value and returns the first column of the first row encountered when the query results in more than one result. Refer to the Help files for more information on available BdpCommand methods.

Because of a special Web page that is part of the .NET Framework, this Web service is easy to test. Just run the Web Service project from the IDE like every other application, selecting Run, Run Without Debugging. This produces a Web page with every available Web Service method (see Figure 17.3). Each of these methods can be invoked by clicking its link, filling in fields (if any), and clicking the Invoke button.

Figure 17.3. The Web Service helper page.

graphics/17fig03.jpg

To test out the new methods added to this Web service, perform the following procedures (assuming the Web service is running with the helper page):

  1. Click the GetProducts link. On the next page, there will be a button titled Invoke. Click it and a new Web page will appear with the XML representation of the DataSet that was returned from calling the GetProducts Web Service method. This XML document contains XML Schema and data. Scroll down to the bottom and observe the last record. On my system it has a rowOrder attribute of 76. Yours will be the same if the table hasn't been altered from the default Northwind database installation. However, the goal is to identify which record was last so that a newly inserted record from the next step can be recognized. Close the XML window and click the browser's Back button on the window to show all the Web methods.

  2. Click the InsertProduct link. On the next page, fill in the fields so that productName is 11111, quantityPerUnit is 5, and unitPrice is 1.25. Click the Invoke button and a blank Web page will appear. If this Web method had returned a value, it would have appeared in XML format on this page, but because the return value is null, the page is blank. Close the blank page, go back to the main page with the Web methods, run the GetProducts method again, and verify that the product named 1111 is the last one in the list. On my system it has a rowOrder attribute of 77, one more than the last time GetProducts was run. Close the XML window and go back to where the Web method list is.

  3. Click on the UpdateProduct link. On the next page fill in the fields so that newProductName is 11111, newQuantityPerUnit is 6, newUnitPrice is 1.25, oldProductName is 11111, oldQuantityPerUnit is 5, and oldUnitPrice is 1.25. Click the Invoke button. Close the blank page that appears, go back to the Web method list, and run the GetProducts Web method to verify that the product name 11111, at the end of the list, has a QuantityPerUnit value of 6. Close the XML window and go back to where the Web method list is.

  4. Click the DeleteProduct link. On the next page fill in the fields so that productName is 11111, quantityPerUnit is 6, and unitPrice is 1.25. Click the Invoke button. Close the blank page that appears, go back to the Web method list, and run the GetProducts Web Method to verify that the product name 11111 is no longer in the list (doesn't show up on the end).

This proves that the Web methods are working and is a quick way to verify that a Web service works before connecting the rest of the network infrastructure. The only limitation of this method is that the helper page only works with primitive type parameters. It does not work with custom types, arrays, or collections. For this, the only real way to test a Web method is to call it with a client application, which is explained later in this chapter.



C# Builder KickStart
C# Builder KickStart
ISBN: 672325896
EAN: N/A
Year: 2003
Pages: 165

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