Web Services

Document Sample
Web Services Powered By Docstoc
					                                             Web Services
                                                  In
                                              ASP.NET
                                           Dr. Awad Khalil
                              Computer Science & Engineering Department
                                                AUC

Introduction
    A web service is a class that allows its methods to be called by methods on other machines via common
     data formats and protocols, such as XML and HTTP. In .NET, the over-the-network method calls are
     commonly implemented through the Simple Object Access Protocol (SOAP), an XML-based protocol
     describing how to mark up requests and responses so that they can be transferred via protocols such as
     HTTP. Using SOAP, applications represent and transmit data in a standardized XML-based format.
    Today, software vendors and e-businesses are encouraged to deploy Web services. An increasing numbers
     of organizations worldwide have connected to the Internet, the concept of applications that call methods
     across a network has become more practical.
    Web services represent the next step in object-oriented programming – rather than developing software
     from a small number of class libraries provided at one location, programmers can access Web service
     class libraries distributed worldwide.
    Web services facilitate collaboration and allow businesses to grow. By purchasing Web services and using
     extensive free Web services that are relevant to their businesses, companies can spend less time
     developing new applications. E-businesses can use Web services to provide their customers with enhanced
     shopping experiences.
    Consider an online music store. The store’s Web site provides links to information about various CDs,
     enabling users to purchase the CDs or to learn about the artists. Another company that sells concert tickets
     provides a Web service that displays upcoming concert dates for various artists, then allows users to buy
     tickets. By consuming the concert-ticket Web service on its site, the online music store can provide an
     additional service to its consumers and increase its site traffic. The company that sells concert tickets also
     benefits from the online music store for the use of its Web service.
    Many services are provided at no charge. For example, Amazon.com and Google offer free Web services
     that you can use in your own applications to access the information they provide.
    Web services have important implications for business-to-business (B2B) transactions. They enable
     businesses to conduct transactions via standardized, widely available Web services rather than relying on
     proprietary applications.
    Web services and SOAP are platform and language independent, so companies can collaborate via Web
     services without worrying about the compatibility of their hardware, software and communications
     technologies.
    Companies such as Amazon.com, Google, eBay and many others are using Web services to their
     advantages.


                                                        1
Limitations
    Web services are not the best solution for certain performance-intensive applications, because
     applications that invoke Web services experience network delays. Also, data transfers are typically larger
     because data is transmitted in text-based XML formats.
    Visual Studio IDE and .NET Framework provide a simple, user-friendly way to create Web services. We
     shall see how to use these tools to create, deploy and use Web services.


.NET Web Services Basics
    A Web service is a software component stored on one machine that can be accessed by an application (or
     other software component) on another machine over a network.
    The machine on which the Web service resides is referred to as a remote machine. The application (i.e.,
     the client) that accesses the Web service sends a method call over the network to the remote machine,
     which processes the call and returns a response over the network to the application.
    This kind of distributed computing benefits various systems. For example, an application without direct
     access to certain data on another system might be able to retrieve this data via a Web service. Similarly, an
     application lacking the processing power necessary to perform specific computations could use a Web
     service to take advantage of another system’s superior resources.
    A Web service is typically implemented as a class. When a client uses a Web service, the class (and its
     compiled DLL) is stored on a remote machine – a compiled version of the Web service is not placed in the
     current application’s directory.
    Requests to and responses from Web services created with Visual Studio IDE are typically transmitted via
     SOAP. So any client capable of generating and processing SOAP messages can interact with a Web
     service, regardless of the language in which the Web service is written.
    It is possible for Web services to limit access to authorized clients. There are standard mechanisms and
     protocols addressing Web service security issues.

Creating a Web Service
    To create a Web service in Visual Studio IDE, you first create a project of type ASP.NET Web Service.
     Visual Studio IDE then generates the following:
           files to contain the Web service code (which implements the Web service)
           An ASMX file (which provides access to the Web service)
           DISCO file (which potential clients use to discover the Web service)
    Visual Studio IDE generates code files for the Web service class and any other code that is part of the
     Web service implementation. In the Web service class, you define the methods that your Web service
     makes available to client applications. Like ASP.NET Web applications, ASP.NET Web services can be
     tested using Visual Studio IDE’s built-in test server. However, to make an ASP.NET Web service publicly
     accessible to clients outside Visual Studio IDE, you must deploy the Web service to a Web server such as
     an Internet Information Services (IIS) Web server.
    Methods in a Web service are invoked through a remote Procedure Call (RPC). These methods, which are
     marked with the WebMethod attribute, are often referred to as Web service methods or simply Web
     methods. Declaring a method with attribute WebMethod makes the method accessible to other classes
     through RPCs and is known as exposing a Web method.

                                                        2
Discovering Web Services
  Once you implement a Web service, compile it and deploy it on a Web server (explained later), a client
    application can consume (i.e. use) the Web service. However, clients be able to find the Web service and
    learn about its capabilities. Discovery of web services (DISCO) is a Microsoft-specific technology used to
    locate Web services on a server. Four types of DISCO files facilitate the discovery process: .disco files,
    .vsdisco files, .discomap files and .map files.
  DISCO files consist of XML markup that describes for clients the location of Web services. A .disco file
    is accessed via a Web service’s ASMX page and contains markup specifying references to the documents
    that define various Web services. The resulting data that is returned from accessing a .disco file is placed
    in the .discomap file.
  A .vsdisco file is placed in Web a Web service’s application directory and behaves in a slightly different
    manner. When a potential client requests a .vsdisco file, XML markup describing the locations of Web
    services is generated dynamically, then returned to the client. First, the .NET Framework searches for
    Web services in the directory in which the .vsdisco file is located, as well as that directory’s
    subdirectories. The .NET Framework then generates XML (using the same syntax as that of a .disco file)
    that contains references to all the Web services found in this search.
  Note that a .vsdisco file does not store the markup generated in response to a request. Instead, the
    .vsdisco file on disk contains configuration settings that specify the .vsdisco file’s behavior. For
    example, developers can specify in the .vsdisco file certain directories that should not be searched when a
    client requests a .vsdisco file. Although a developer can open a .vsdisco file in a text editor and examine
    its contents, this is rarely necessary – a .vsdisco file is intended to be requested (i.e., viewed in a browser)
    by clients over the Web. Every time this occurs, new markup is generated and displayed.
  Using .vsdico files benefits developers in several ways. These files contain only a small amount of data
    and provide up-to-date information about a server’s available Web services. However, .vsdisco files
    generate more overhead (i.e., require more processing) than .disco files do, because a search must be
    performed every time a .vsdisco file is accessed. Thus, some developers find it more beneficial to update
    .disco files manually. Many systems use both types of files. As we discuss shortly, Web services created
    using ASP.NET contain the functionality to generate a .disco file when it is requested. This .disco file
    contains references only to files in the current Web service. Thus, a developer typically places a .vsdisco
    file at the root of a server, when accessed, this file locates the .disco files for Web services anywhere on
    the system and uses the markup found in these .disco files to return information about the entire system.

Determining a Web Service’s Functionality
  After locating a Web service, the client must determine the Web service’s functionality and how to use it.
    For this purpose, Web services normally contain a service description. This is an XML document that
    conforms to the Web Service Description Language (WSDL) – an XML vocabulary that defines the
    methods a Web service makes available and how clients interact with them. The WSDL document also
    specifies lower-level information that clients might need, such as the required formats for requests and
    responses.
  WSDL documents are not meant to be read by developers; rather, WSDL documents are meant to be read
    by applications, so they know how to interact with the Web services described in the documents. IDE
    generates an ASMX file when a Web service is constructed . Files with the .asmx filename extension are
    ASP.NET Web service files and are executed by ASP.NET on a Web server (e.g., IIS).
  When viewed in a Web browser, an ASMX file presents Web method descriptions and links to test pages
                                                         3
    that allow users to execute sample calls to these methods. The ASMX file also specifies the Web service’s
    implementation class, and optionally the code-behind file in which the Web service is defined and the
    assemlies referenced by the Web service.
   When the Web server receives a request for the Web service, it accesses the ASMX file, which in turn,
    invokes the Web service implementation. To view more technical information about the Web service,
    developers can access the WSDL file (which is generated by ASP.NET).
   The following ASMX page displays information about the HugeInteger Web service that we will create
    later. This Web service is designed to perform calculations with integers that contain a maximum of 100
    digits. Most programming languages cannot easily perform calculations using integers this large.




   The Web service HugeInteger provides client applications with methods that take two “huge integers”
    and determine their sum, their difference, which one is larger or smaller and whether the two numbers are
    equal.
   Generating the WSDL description dynamically ensures that clients receive the most current information
    about the Web service. It is common for an XML document (such as a WSDL description) to be created
    dynamically and not saved to disk. When a user clicks the Service Description link at the top of the Note
    that the top of the page provides a link to the Web service’s Service Description. ASP.NET generates the
    WSDL service description from the code you write to define the Web service. Client programs use a Web
    service’s service description to validate Web method calls when the client programs are compiled
                                                     4
   ASP.NET generates WSDL information dynamically rather than creating an actual WSDL file. If a client
    requests the Web service’s WSDL description (either by appending ?WSDL to the ASMX file’s URL or
    by clicking the Service Description link), ASP.NET generates the WSDL description, then returns it to
    the client for display in the Web browser.
   ASMX page, the browser displays the generated WSDL document containing the service description.




Testing a Web Service’s Methods
  Below the Service Description link, the ASMX page lists the methods that the Web service offers.
   Clicking any method name requests a test page that describes the method. The test page allows users to
   test the method by entering parameter values and clicking the Invoke button.
  Below the Invoke button, the page displays sample request-and-response messages using SOAP and
   HTTP POST. These protocols are two options for sending and receiving messages in Web services.
  The protocol that transmits request-and-response messages is also known as the Web service’s wire
   format or wire protocol, because it defines how information is sent “along the wire.”
  SOAP is the more commonly used wire format, because SOAP messages can be sent using several
   transport protocols, whereas HTTP POST must use HTTP. When you test a Web service via an ASMX
   page, the ASMX page uses HTTP POST to test the Web service methods. Later, when we use Web
   services in our C# programs, we employ SOAP – the default protocol for .NET Web services.
  The following figure depicts the test page for the HugeInteger Web method Bigger. From this page,
                                                   5
users can test the method by entering values in the first: and second: fields, then clicking Invoke. The
method executes, and a new Web browser window opens, displaying an XML document that contains the
result.




                                                6
Building a Client to Use a Web Service
  A .NET client can be any type of .NET application, such as Windows application, a console application or
     a Web application. You can enable a client application to consume a Web service by adding a Web
     reference to the client. This process adds files to the client application that allow the client to access the
     Web service.
  To add a Web reference in Visual C#, right click the project name in the Solution Explorer and select
     Add Web Reference…. In the resulting dialog, specify the Web service to consume. Visual C# then
     adds an appropriate Web reference to the client application.
  When you specify the Web service you want to consume, Visual C# accesses the Web service’s WSDL
     information and copies it into a WSDL file that is stored in the client project’s Web References folder.
     This file is visible when you instruct Visual C# to Show All Files.
  Note that a copy of the WSDL file provides the client application with local access to the Web service’s
     description. To ensure that the WSDL file is up-to-date, Visual C# provides an Update Web Reference
     option which updates the files in the Web References folder.
  The WSDL information is used to create a proxy class, which handles all the “plumbing” required for
     Web method calls (i.e., networking details and the formation of SOAP messages).
  Whenever the client application calls a Web method, the application actually calls a corresponding method
     in the proxy class. This method has the same name and parameters as the Web method that is being called,
     but formats the call to be sent as a request in a SOAP message.
  The Web service receives this request as a SOAP message, executes the method call and sends back the
     result as another SOAP message.
  When the client application receives the SOAP message containing the response, the proxy class
     deserializes it and returns the results as the return value of the Web method that was called.
  The following figure depicts the interactions among the client node, proxy class and Web service.
  The .NET environment hides most of these details from you. Many aspects of Web service creation and
     consumption – such as generating WSDL files, proxy classes and DISCO files – are handled by Visual
     Studio IDE.

Simple Object Access Protocol (SOAP)
    The Simple Object Access Protocol (SOAP) is a platform-independent protocol that uses XML to make
     remote procedure calls, typically over HTTP. Each request and response is packaged in a SOAP message
     – an XML message containing the information that a Web service requires to process the message.
    SOAP messages are written in XML so that they are human readable and platform independent.
    Most firewalls – security barriers that restrict communication among networks – do not restrict HTTP
     traffic. Thus, XML and HTTP enable computers on different platforms to send and receive SOAP
     messages with few limitations.
    Web services also use SOAP for the extensive set of types it supports. The wire format used to transmit
     requests and responses must support all types passed between the applications. SOAP types include the
     primitive types (e.g., Integer), as well DateTime, XmlNode and others. SOAP can also transmit arrays of
     all these types. In addition, DataSets can be serialized into SOAP. You can also transmit user-defined
     types in SOAP messages.
    When a program invokes a Web method, the request and all relevant information are packaged in a SOAP
     message and sent to the server on which the Web service resides.
    When the Web service receives this SOAP message, it begins to process the contents (contained in a
     SOAP envelope), which specify the method that the client wishes to execute and any arguments the client
                                                        7
     is passing to that method. This process of interpreting a SOAP message’s contents is known as parsing a
     SOAP message. After the Web service receives and parses a request, the proper method is called with the
     specified arguments (if there are any), and the response is sent back to the client in another SOAP
     message. The client parses the response to retrieve the result of the method call.
    The following SOAP request was taken from the test page for the HugeInteger Web service’s Bigger
     method. Visual C# creates such a message when a client wishes to execute the HugeInteger Web
     service’s Bigger method. If the client is a Web application, Visual IDE creates the SOAP message. The
     message contains placeholders (length in line 4 and string in lines 16-17) representing values specific to a
     particular call to Bigger
    If this were a real SOAP request, elements first and second (lines 16-17) would each contain an actual
     value passed from the client to the Web service, rather than the placeholder string. For example, if this
     envelope were transmitting the request, element first and element second would contain the numbers and
     placeholder length (line 4) would contain the length of the SOAP message.
    Most programmers do not manipulate SOAP messages directly, but instead allow the .NET framework to
     handle the transmission details.
      1. POST /HugeInteger/HugeInteger.asmx HTTP/1.1
      2. Host: localhost
      3. Content-Type: text/xml; charset=utf-8
      4. Content-Length: length
      5. SOAPAction: http://deitel.com/Bigger
      6.
      7. <?xml version=“1.0” encoding=“utf-8” ?>
      8.
      9. <soap:Envelope
      10.    xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
      11.    xmlns:xsd=http://www.w3.org/2001/XMLSchema
      12.    xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/>
      13.
      14.    <soap:body>
      15.       <Bigger xmlns=“http://www.deitel.com”>
      16.          <first>string</first>
      17.          <second>string</second>
      18.        </Bigger>
      19.    <soap:body>
      20. </soap:Envelope>

Publishing and Consuming Web Services
    This section presents several examples of creating (also known as publishing) and using (also known as
     consuming) Web services.
    Recall that an application that consumes a Web service actually consists of two parts – a proxy class
     representing the Web service and a client application that accesses the Web service via an instance of the
     proxy class.
    The instance of the proxy class passes a Web method’s arguments from the client application to the Web
     service. When the Web service completes its task, the instance of the proxy class receives the result and
     parses it for the client application.
                                                       8
Defining the HugeInteger Web Service
    The following presents the code-behind for the HugeInteger Web service that we will create later.
    When creating Web services in Visual Studio IDE, you work almost exclusively in the code-behind file.
    The HugeInteger Web service is designed to perform calculations with integers that have a maximum
      of 100 digits. long variables cannot handle integers of this size (i.e., an overflow occurs). The Web
      service provides methods that take two “huge integers” (represented as strings) and determine their sum,
      their difference, which one is larger or smaller and whether the two numbers are equal.
    You can think of these methods as services available to programmers of other applications via the Web
      (hence the term Web services). Any programmer can access this Web service, use the methods and thus
      avoid writing 172 lines of code.
           1. // HugeInteger.cs
           2. // HugeInteger Web service performs operations on large integers.
           3. using System;
           4. using System.Web;
           5. using System.Web.Services;
           6. using System.Web.Services.Protocols;
           7.
           8. [ WebService( Namespace = "http://www.deitel.com/",
           9.    Description = "A Web service that provides methods for" +
           10. " manipulating large integer values" ) ]
           11. [ WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 ) ]
           12. public class HugeInteger : System.Web.Services.WebService
           13. {
           14. private const int MAXIMUM = 100; // maximum number of digits
           15. public int[] number; // array representing the huge integer
           16.
           17. // default constructor
           18. public HugeInteger()
           19. {
           20.     number = new int[ MAXIMUM ];
           21. } // end default constructor
           22.
           23. // indexer that accepts an integer parameter
           24. public int this[ int index ]
           25. {
           26.     get
           27.     {
           28.        return number[ index ];
           29.     } // end get
           30.
           31. set
           32.     {
           33.        number[ index ] = value;
           34.     } // end set
           35. } // end indexer
                                                      9
36.
37.    // returns string representation of HugeInteger
38.    public override string ToString()
39.    {
40.       string returnString = "";
41.
42.      foreach ( int i in number )
43.        returnString = i + returnString;
44.
45.       return returnString;
46.    } // end method ToString
47.
48.   // creates HugeInteger based on argument
49.     public static HugeInteger FromString( string value )
50.     {
51.       // create temporary HugeInteger to be returned by the method
52.       HugeInteger parsedInteger = new HugeInteger();
53.
54.      for ( int i = 0 ; i < value.Length; i++ )
55.        parsedInteger[ i ] = Int32.Parse(
56.           value[ value.Length - i - 1 ].ToString() );
57.
58.       return parsedInteger;
59.    } // end method FromString
60.
61.    // WebMethod that adds integers represented by the String arguments
62.    [ WebMethod( Description="Adds two huge integers." ) ]
63.   public string Add( string first, string second )
64.    {
65.       int carry = 0;
66.       HugeInteger operand1 = HugeInteger.FromString( first );
67.       HugeInteger operand2 = HugeInteger.FromString( second );
68.       HugeInteger result = new HugeInteger(); // stores result of addition
69.
70.      // perform addition algorithm for each digit
71.      for ( int i = 0; i < MAXIMUM; i++ )
72.      {
73.         // add two digits in same column,
74.         // result is their sum plus carry from
75.         // previous operation, modulo 10
76.         result[ i ] =
77.            ( operand1[ i ] + operand2[ i ] + carry ) % 10;
78.
79.   // set carry to remainder of dividing sums of two digits by 10
80.         carry = ( operand1[ i ] + operand2[ i ] + carry ) / 10;

                                              10
81.     } // end for
82.
83.     return result.ToString();
84. } // end method Add
85.
86. // WebMethod that subtracts integers
87. // represented by the string arguments
88. [ WebMethod( Description="Subtracts two huge integers." ) ]
89. public string Subtract( string first, string second )
90. {
91.     HugeInteger operand1 = HugeInteger.FromString( first );
92.     HugeInteger operand2 = HugeInteger.FromString( second );
93.     HugeInteger result = new HugeInteger();
94.
95. // subtract bottom digit from top digit
96.     for ( int i = 0; i < MAXIMUM; i++ )
97.     {
98.        // if top digit is smaller than bottom digit we need to borrow
99.        if ( operand1[ i ] < operand2[ i ] )
100.                     Borrow( operand1, i );
101.
102.                  // subtract bottom from top
103.                  result[ i ] = operand1[ i ] - operand2[ i ];
104.               } // end for
105.
106.               return result.ToString();
107.            } // end method Subtract
108.
109.          // borrow 1 from next digit
110.            private void Borrow( HugeInteger hugeInteger, int place )
111.            {
112.               // if no place to borrow from, signal problem
113.               if ( place >= MAXIMUM - 1 )
114.                  throw new ArgumentException();
115.
116.               // otherwise if next digit is zero, borrow from column to left
117.               else if ( hugeInteger[ place + 1 ] == 0 )
118.                  Borrow( hugeInteger, place + 1 );
119.
120.               // add ten to current place because we borrowed and subtract
121.               // one from previous digit--this is the digit we borrowed from
122.               hugeInteger[ place ] += 10;
123.               hugeInteger[ place + 1 ]--;
124.            } // end method Borrow
125.

                                          11
126.   // WebMethod that returns true if first integer is bigger than second
127.     [ WebMethod( Description="Determines whether the first integer is " +
128.       "larger than the second integer." ) ]
129.     public bool Bigger( string first, string second )
130.     {
131.       char[] zeros = { '0' };
132.
133.        try
134.        {
135.           // if elimination of all zeros from result
136.           // of subtraction is an empty string,
137.           // numbers are equal, so return false, otherwise return true
138.           if ( Subtract( first, second ).Trim( zeros ) == "" )
139.              return false;
140.           else
141.              return true;
142.        } // end try
143.   // if ArgumentException occurs, first
144.        // number was smaller, so return false
145.        catch ( ArgumentException exception )
146.        {
147.           return false;
148.        } // end catch
149.     } // end method Bigger
150.
151.    // WebMethod returns true if first integer is smaller than second
152.    [ WebMethod( Description="Determines whether the first integer " +
153.       "is smaller than the second integer." ) ]
154.    public bool Smaller( string first, string second )
155.    {
156.       // if second is bigger than first, then first is smaller than second
157.       return Bigger( second, first );
158.    } // end method Smaller
159.
160.   // WebMethod that returns true if two integers are equal
161.      [ WebMethod( Description="Determines whether the first integer " +
162.        "is equal to the second integer." ) ]
163.      public bool EqualTo( string first, string second )
164.      {
165.        // if either first is bigger than second, or first is
166.        // smaller than second, they are not equal
167.        if ( Bigger( first, second ) || Smaller( first, second ) )
168.           return false;
169.        else
170.           return true;

                                      12
         171.           } // end method EqualTo
         172.        } // end class HugeInteger



   Lines 8-10 contain a WebService attribute. Attaching this attribute to a Web service class declaration
    allows you to specify the Web service’s namespace and description. Like an XML namespace, a Web
    service’s namespace is used by client applications to differentiate that Web service from other available on
    the Web.
   Line 8 assigns http://www.deitel.com as the Web service’s namespace using the WebService attribute’s
    Namespace property.
   Lines 9-10 use the WebService attribute’s Description property to describe the Web service’s purpose –
    this appears in the ASMX page.
   Visual Studio IDE places line 11 in all newly created Web services. This line indicates that the Web
    service confirms to the Basic Profile 1.1 (BP 1.1) developed by the Web Services Interoperability
    Organization (WS-1), a group dedicated to promoting interoperability among Web services developed on
    different platforms with different programming languages. BP 1.1 is a document that defines best
    practices for various aspects of Web service creation and consumption (www.WS-I.org).
   .NET environment hides many of these details from you. Setting the WebServiceBinding attribute’s
    ConformsTo property to WsiProfile.BasicProfile1_1 instructs Visual Studio IDE to perform its “behind-
    the-scenes” work, such as generating WSDL and ASMX files, in conformance with the guidelines laid out
    in BP 1.1.
   By default, each new Web service class created in Visual studio IDE inherits from class
    System.Web.Services.WebService (line 12). Although a Web service need not derive from class
    WebService, this class provides members that are useful in determining information about the client and
    the Web service itself.
   Several methods in class HugeInteger are tagged with the WebMethod attribute (lines 62, 88, 127, 152
    and 161), which exposes a method so that it can be called remotely. When this attribute is absent, the
    method is not accessible to clients that consume the Web service.
   Note that this attribute, like the WebService attribute, contains a Description property that allows the
    ASMX page to display information about the method.
   Lines 24-35 define an indexer, which enables us to access any digit in a HugeInteger.
   Lines 62-84 and 88-107 define Web methods Add and Subtract, which perform addition and subtraction,
    respectively. Method Borrow (lines 110-124) handles the case in which the digit that we are currently
    examining in the left operand is smaller than the corresponding digit in the right operand. For instance,
    when we subtract 19 from 32, we usually examine the numbers in the operands digit-by-digit, starting
    from the right. The number 2 is smaller than 9, so we add 10 to 2 (resulting in 12). After borrowing, we
    can subtract 9 from 12, resulting in 3 for the rightmost digit in the solution. We then subtract 1 from the 3
    in 32 – the next digit to the left (i.e., the digit we borrowed from). This leaves a 2 in the tens place. The
    corresponding digit in the other operand is now 1 in 19. subtracting 1 from 2 yields 1, making the
    corresponding digit in the result 1. The final result, when the digits are put together, is 13.
   Method Borrow is the method that adds 10 to the appropriate digits and subtracts 1 from the digits to the
    left. This is a utility method that is not intended to be called remotely, so it is not qualified with attribute
    WebMethod.


                                                       13
Building a Web Service in Visual Studio IDE
    We now show how to create the HugeInteger Web service. In the following steps, you will create an
     ASP.NET Web Service project that executes on your computer’s local IIS Web server. To create the
     HugeInteger Web service in Visual Studio IDE, perform the following steps:


Step1: Creating the Project
  To begin, we must create a project of type ASP.NET Web Service.
  Select File > New Web Site… to display the New Web Site dialog. Select ASP.NET Web Service in
    the Templates pane. Select HTTP from the Location drop-down list to indicate that the files should be
    placed on a Web server. By default, Visual Studio IDE indicates that it will place the files on the local
    machine’s IIS Web server in a virtual directory named WebSite (http://localhost/WebSite).
  Replace the name WebSite with HugeInteger for this example.
  Next, select Visual C# from the Language drop-down list to indicate that you will use Visual C# to build
    the Web service.
  Visual Studio IDE places the Web service project’s solution file (.sln) in the Projects subfolder within the
    current Windows user’s My Documents\Visual Studio 2008 folder. If you don’t have access to an IIS
    Web server to build ant test the examples, you can select File System from the Location drop-down list.
    In this case, IDE will place the Web service’s files on your local hard disk. You will be then be able to test
    the Web server using IDE’s built-in Web server.




                                                       14
Step2: Examining the Newly Created Project
  When the project is created, the code-behind file service.cs, which contains code for a simple Web
    service is displayed by default.
  If the code-behind file is not open, it can be opened by double clicking the file in the App_Code directory
    listed in the Solution Explorer.
  Visual Studio IDE includes four using declarations that are helpful for developing Web services (lines 1-
    4).
  By default, a new code-behind file defines a class named Service that is marked with the WebService
    and WebServiceBinding attributes (lines 6-7).
  The class contains a sample Web method named HelloWorld (lines 14-17). This method is a placeholder
    that you will replace with your own method(s).




Step 3: Modifying and Renaming the Code-Behind File
  To create the HugeInteger Web service, modify Service.cs by replacing all of the sample code provided
    by Visual Studio IDE with all of the code from the HugeInteger code-behind file. Then rename the
    HugeInteger.cs.

Step 4: Examining the ASMX File
  The Solution Explorer lists one file – Service.asmx – in addition to the code-behind file.
  Recall that a Web service’s ASMX page, when accessed through a Web browser, displays information
    about the Web service’s methods and provides access to the Web service’s WSDL information.
  However, if you open the ASMX file on disk, you will see that it actually contains only:
  <%@ WebService Language=“C#” CodeBehind=“~/App_Code/Service.cs” Class=“Service” %>
  to indicate the programming language in which the Web service’s code-behind file is written, the code-
                                                     15
     behind file’s location and the class that defines the Web service. When you will request the ASMX page
     through IIS, ASP.NET uses this information to generate the content displayed in the Web browser.

Step 5: Modifying the ASMX File
     Whenever you change the name of the code-behind file or the name of the class that defines the Web
       service, you must modify the ASMX file accordingly. Thus, after defining class HugeInteger in the
       code-behind file HugeInteger.cs, modify the ASMX file to contain the lines:
     <%@ WebService Language=“C#” CodeBehind = “~/App_Code/HugeInteger.cs” Class =
       “HugeInteger” %>

Step 6: Renaming the ASMX File
  The final step in creating the HugeInteger Web service is to rename the ASMX file HugeInteger.asmx

Deploying the HugeInteger Web Service
  The Web service is already deployed because we created the HugeInteger Web service directly to our
    computer’s local IIS server.
  You can choose Build Web Site from the Build menu to ensure that the Web service compiles without
    errors.
  You can also test the Web service directly from Visual Studio IDE by selecting Start Without Debugging
    from the Debug menu. This opens a browser window that contains the following ASMX page. Clicking
    the link for a particular HugeInteger Web service method displays a Web page that allows you to test the
    method, as we have shown before.
  Note that you can also access the Web service’s ASMX page from your computer by typing the following
    URL in a Web browser:

                             http://localhost/HugeInteger/HugeInteger.asmx

Accessing the HugeInteger Web Service’s ASMX Page from Another Computer
        Eventually, you will want other clients to be able to access and use your Web service. If you deploy
           the Web service on an IIS Web server, a client can connect to that server to access the Web service
           with a URL of the form:
               http://host/HugeInteger/HugeInteger.asmx
   where host is the hostname or IP address of the Web server.
  To access the Web service from another computer in your company’s or school’s local area network, you
    can replace host with the actual name of the computer on which IIS is running.
  If you have the Windows XP Service Pack 2 operating system on the computer running IIS, that computer
    may not allow requests from other computers by default. If you wish to allow other computers to connect
    to your computer’s Web server, perform the following steps:
  Select Start > Control Panel to open your system’s Control Panel window, then double click Windows
    Firewall to view the Windows Firewall settings dialog.
  In the Windows Firewall settings dialog, click the Advanced tab, select Local Area Connection (or
    your network connection’s name, if it is different if it is different) in the Network Connection Settings
    list box and click the Settings… button to display the Advanced Settings dialog.
  In the Advanced Settings dialog, ensure that the checkbox for Web Server (HTTP) is checked to allow
    clients on other computers to submit requests to your computer’s Web server.

                                                     16
    Click OK in the Advanced Settings dialog, then click OK in the Windows Firewall settings dialog.
    Accessing the HugeInteger Web Service’s ASMX Page When the Web Service Executes in
     Visual Studio IDE’s Built-in Web Server
    Recall that if you don’t have access to an IIS server to deploy and test your Web service, you can create
     the Web service on your computer’s hard disk and use Visual Studio IDE’s built-in Web server to test the
     Web service. In this case you select Start Without Debugging from the Debug menu. IDE executes its
     built-in Web server, then opens a Web browser containing the Web service’s ASMX page so that you can
     test the Web service.
    Web servers typically receive requests on port 80. To ensure that IDE’s built-in Web server does not
     conflict with another Web server running on your local computer. IDE’s Web server receives requests on
     a randomly selected port number. When a Web server receives requests on a port number other than port
     80, the port number must be specified as part of the request. In this case, the URL to access the
     HugeInteger Web service’s ASMX page would be of the form:
               http://host:portNumber/HugeInteger/HugeInteger.asmx
        where host is the hostname or IP address of the computer on which IDE’s built-in Web server is
        running and portNumber is the specific port on which the Web server receives requests. You can see
        this port number in your Web browser’s Address field when you test the Web service from IDE.

Creating a Client to Consume the HugeInteger Web service
    Now that we have defined and deployed our Web service, we demonstrate how to consume it from a client
     application. In this section, we will create a Windows application as the client using Visual C# . After
     creating the client application, you will add a proxy class to the project that allows the client to access the
     Web service.
    Recall that the proxy class (or proxy) is generated from the Web service’s WSDL file and enables the
     client to call Web methods over the Internet. The proxy class handles all the details of communicating
     with the Web service. The proxy class is hidden from you by default – you can view it in the Solution
     Explorer by clicking the Show All Files button. The proxy class’s purpose is to make clients think that
     they are calling the Web methods directly. The following example demonstrates how to create a Web
     service client and generate a proxy class that allows the client to access the HugeInteger Web service.
     You will begin by creating a project and adding a Web reference to it. When you add the Web reference,
     Visual C# will generate the appropriate proxy class. You will then create an instance of the proxy class
     and use it to call the Web service’s methods. First, create a Windows application in Visual C#, then
     perform the following steps:

Step 1: Opening the Add Web Reference Dialog
  Right click the project name in the Solution Explorer and select ADD Web Reference….




                                                        17
18
Step 2: Locating Web Services on Your Computer
  In the Add Web Reference dialog, click Web services on the local machine to locate Web references
    stored on the IIS Web server on your local computer (http://localhost). This server’s files are located at
    C:\Inetpub\wwwroot by default.
  Note that the Add Web Reference dialog allows you to search for Web services in several different
    locations. Many companies that provide Web services simply distribute the exact URLs at which their
    Web services can be accessed. For this reason, the Add Web Reference dialog also allows you to enter
    the specific URL of a Web service in the URL field.

Step 3: Choosing the Web Service to Reference
       Select the HugeInteger Web service from the list of available Web services.

Step 4: Adding the Web Reference
  Add the Web reference by clicking the Add Reference button.

Step 5: Viewing the Web Reference in the Solution Explorer
  The Solution Explorer should now contain a Web References folder with a node named after the
    domain name where the Web service is located. In this case, the name is localhost because we are using
    the local Web server. When we reference class HugeInteger in the client application, we will do so
    through the localhost namespace.
  Notes on Creating a Client to Consume a Web Service
  The steps we just presented also apply to adding Web references to Web applications created in IDE.
    When creating a client to consume a Web service, add the Web reference first so that Visual C# (or IDE)
    can recognize an object of the Web service proxy class. Once you add the Web reference to the client, it
    can access the Web service through an object of the proxy class. The proxy class (named HugeInteger) is
    located in namespace localhost, so you must use localhost.HugeInteger to reference this class.
  Although you must create an object of the proxy class to access the Web service, you do not need access
    to the proxy class’s code. You can invoke the proxy object’s methods as if it were an object of the Web
    service class.
  The steps that we described in this section work well if you know the appropriate Web service reference.
    However, what if you are trying to locate a new Web service? Two common technologies facilitate this
    process – Universal Description, Discovery and Integration (UDDI) and Discovery of Web services
    (DISCO). You can learn more about UDDI and view demonstration by visiting www.uddi.org and
    uddi.microsoft.com. These sites contain search tools that make finding Web services convenient.

Consuming the HugeInteger Web Service
  The following Windows Form uses the HugeInteger Web service to perform computations with positive
    integers up to 100 digits long.


           1.    // UsingHugeIntegerService.cs
           2.   // Using the HugeInteger Web Service.
           3.   using System;
           4.   using System.Collections.Generic;
           5.   using System.ComponentModel;

                                                     19
6. using System.Data;
7. using System.Drawing;
8. using System.Text;
9. using System.Windows.Forms;
10. using System.Web.Services.Protocols;
11.
12. namespace UsingHugeIntegerWebService
13. {
14. public partial class UsingHugeIntegerServiceForm : Form
15. {
16.      public UsingHugeIntegerServiceForm()
17.      {
18.         InitializeComponent();
19.      } // end constructor
20.
21.      // declare a reference to Web service
22.      private localhost.HugeInteger remoteInteger;
23.
24.      private char[] zeros = { '0' }; // character to trim from strings
25.
26. // instantiates object to interact with Web service
27.      private void UsingHugeIntegerServiceForm_Load( object
28.             sender,       EventArgs e )
29.      {
30.         // instantiate remoteInteger
31.         remoteInteger = new localhost.HugeInteger();
32.      } // end method UsingHugeIntegerServiceForm_Load
33.
34.      // adds two numbers input by user
35.      private void addButton_Click( object sender, EventArgs e )
36.      {
37.         // make sure numbers do not exceed 100 digits and that both
38.         // are not 100 digits long, which would result in overflow
39.         if ( firstTextBox.Text.Length > 100 ||
40.            secondTextBox.Text.Length > 100 ||
41.            ( firstTextBox.Text.Length == 100 &&
42.            secondTextBox.Text.Length == 100) )
43. {
44.            MessageBox.Show( "HugeIntegers must not be more " +
45.               "than 100 digits\r\nBoth integers cannot be " +
46.               "of length 100: this causes an overflow", "Error",
47.               MessageBoxButtons.OK, MessageBoxIcon.Information );
48.            return;
49.         } // end if
50.

                                         20
51.         // perform addition
52.         resultLabel.Text = remoteInteger.Add(
53.            firstTextBox.Text, secondTextBox.Text ).TrimStart( zeros );
54.      } // end method addButton_Click
55.
56. // subtracts two numbers input by user
57.      private void subtractButton_Click( object sender, EventArgs e )
58.      {
59.         // make sure HugeIntegers do not exceed 100 digits
60.         if ( SizeCheck( firstTextBox, secondTextBox ) )
61.            return;
62.
63.         // perform subtraction
64.         try
65.         {
66.            string result = remoteInteger.Subtract(
67.             firstTextBox.Text, secondTextBox.Text ).TrimStart( zeros );
68.
69.            if ( result == "" )
70.               resultLabel.Text = "0";
71.            else
72. resultLabel.Text = result;
73.
74.         } // end try
75.
76.         // if WebMethod throws an exception,
77.         // then first argument was smaller than second
78.         catch ( SoapException exception )
79.         {
80.            MessageBox.Show(
81.               "First argument was smaller than the second" );
82.         } // end catch
83.      } // end method subtractButton_Click
84.
85.      // determines whether first number
86.      // input by user is larger than second
87. private void largerButton_Click( object sender, EventArgs e )
88.      {
89.         // make sure HugeIntegers do not exceed 100 digits
90.         if ( SizeCheck( firstTextBox, secondTextBox ) )
91.            return;
92.
93.         // call Web-service method to determine if
94.         // first integer is larger than the second
95.         if ( remoteInteger.Bigger( firstTextBox.Text,

                                          21
96.    secondTextBox.Text ) )
97.    resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
98.      " is larger than " +
99.      secondTextBox.Text.TrimStart( zeros );
100.          else
101.   resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
102.              " is not larger than " +
103.              secondTextBox.Text.TrimStart( zeros );
104.       } // end method largerButton_Click
105.
106.      // determines whether first number
107.      // input by user is smaller than second
108.      private void smallerButton_Click( object sender, EventArgs e )
109.      {
110.         // make sure HugeIntegers do not exceed 100 digits
111.         if ( SizeCheck( firstTextBox, secondTextBox ) )
112.            return;
113.
114.        // call Web-service method to determine if
115.        // first integer is smaller than second


116.   if ( remoteInteger.Smaller( firstTextBox.Text,
117.             secondTextBox.Text ) )
118.             resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
119.               " is smaller than " +
120.               secondTextBox.Text.TrimStart( zeros );
121.           else
122.             resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
123.               " is not smaller than " +
124.               secondTextBox.Text.TrimStart( zeros );
125.        } // end method smallerButton_Click
126.
127.   // determines whether two numbers input by user are equal
128.       private void equalButton_Click( object sender, EventArgs e )
129.       {
130.         // make sure HugeIntegers do not exceed 100 digits
131.         if ( SizeCheck( firstTextBox, secondTextBox ) )
132.            return;
133.
134.        // call Web-service method to determine if integers are equal
135.        if ( remoteInteger.EqualTo( firstTextBox.Text,
136.           secondTextBox.Text ) )
137.           resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
138.              " is equal to " + secondTextBox.Text.TrimStart( zeros );

                                     22
           139.                else
           140.                   resultLabel.Text = firstTextBox.Text.TrimStart( zeros ) +
           141.                      " is not equal to " +
           142.                      secondTextBox.Text.TrimStart( zeros );
           143.             } // end method equalButton_Click
           144.
           145.       // determines whether numbers input by user are too big
           146.             private bool SizeCheck( TextBox first, TextBox second )
           147.             {
           148.           // display an error message if either number has too many digits
           149.                if ( ( first.Text.Length > 100 ) ||
           150.                   ( second.Text.Length > 100 ) )
           151.                {
           152.        MessageBox.Show( "HugeIntegers must be less than 100 digits" ,
           153.          "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
           154.                   return true;
           155.                } // end if
           156.
           157.                return false;
           158.             } // end method SizeCheck
           159.          } // end class UsingHugeIntegerServiceForm
           160.       } // end namespace UsingHugeIntegerWebService
    Line 22 declares variable remoteInteger of type localhost.HugeInteger. This variable is used in each of
     the application’s event handlers to call methods of the HugeInteger Web service.
    The proxy object is created and assigned to this variable in the Form’s Load event handler.
    Lines 52-53, 66-67, 95-96, 116-117 and 135-136 in the various button event handlers invoke methods of
     the Web service. Note that each call is made on the local proxy object, which then communicates with the
     Web service on the client’s behalf.
    The user inputs two integers, each up to 100 digits long. Clicking a button causes the application to invoke
     a Web method to perform the appropriate task and return the result. Note that client application
     UsingHugeIntegerService cannot perform operations using 100-digit numbers directly. Instead the
     application creates string representations of these numbers and passes them as arguments to Web methods
     that handle such tasks for the client. It then uses the return value of each operation to display an
     appropriate message.
    Note that the application eliminates leading zeros in the numbers before displaying them by calling string
     method TrimStart. Like string method Trim, TrimStart removes all occurrences of characters specified
     by a char array (line 24) from the beginning of a string.

Session Tracking in Web Services
    In this section, we will incorporate session tracking into a Web service. Suppose a client application
     needs to call several methods from the same Web service, possibly several times each. In such a case, it
     can be beneficial for the Web service to maintain state information for the client.
    Session tracking eliminates the need for information about the client to be passed between the client and
     the Web service multiple times. For example, a Web service providing access to local restaurant reviews
     would benefit from storing the client user’s street address. Once the user’s address is stored in a session
                                                      23
    variable, Web methods can return personalized, localized results without requiring that the address be
    passed in each method call. This is not only improves performance, but also requires less effort on the part
    of the programmer – less information is passed in each method call.

Creating a Blackjack Web Service
      Storing session information can provide client programmers with a more intuitive Web service. Our
        next example is a Web service that assists programmers in developing a blackjack card game.
      The Web service provides Web methods to deal a card and to evaluate a hand of cards. After
        presenting the Web service, we use it to serve as the dealer for a game of blackjack.
      The blackjack Web service uses a session variable to maintain a unique deck of cards for each client
        application. Several clients can use the service at the same time, but Web method calls made by a
        specific client use only the deck stored in that client’s session. Our example uses a simple subset of
        casino blackjack rules.
      The Web service provides methods to deal a card and to determine the point value of a hand. We
        represent each card as a string consisting of digits (e.g., 1-13) representing the card’s face (e.g., ace
        through kings), followed by a space and a digit (e.g., 0-3) representing the card’s suit (e.g., clubs,
        diamonds, hearts or spades). For example, the jack of hearts is represented as “11 2” and the two of
        clubs is represented as “2 0”.
      After deploying the Web service, we create a Windows application that uses the
        BlackjackService’s Web methods to implement a game of blackjack. To create and deploy this
        Web service we can follow the same steps of creating and deploying the HugeInteger Web service.


      Blackjack Rules
     Two cards each are dealt to the dealer and the player. The player’s cards are dealt face up. Only the first
      of the dealer’s cards is dealt face up. Each card has a value. A card numbered 2 to 10 is worth its face
      value. Jacks, queens and kings each count as 10. aces can count as 1 or 11 – whichever value is more
      beneficial to the player. If the sum of the player’s two initial cards is 21 (i.e., the player was dealt a
      card valued at 10 and an ace, which counts as 11 in this situation), the player has “blackjack” and
      immediately wins the game. Otherwise, the player can begin taking additional cards one at a time.
      These cards are dealt face up, and the player decides when to stop taking cards. If the player “busts”
      (i.e., the sum of the player’s cards exceeds 21), the game is over, and the player loses. When the player
      is satisfied with the current set of cards, the player “stays” (i.e., stops taking cards), and the dealer’s
      hidden card is revealed. If the dealer’s total is 16 or less, the dealer must take another card; otherwise,
      the dealer must stay. The dealer must continue to take cards until the sum of the dealer’s cards is
      greater than or equal 17. if the dealer exceeds 21, the player wins. Otherwise, the hand with the higher
      point total wins. If the dealer and the player have the same point total, the game is a “push” (i.e., a tie)
      and no one wins.

      1.   // BlackjackService.cs
      2.   // Blackjack Web Service deals and counts cards.
      3.   using System;
      4.   using System.Web;
      5.   using System.Web.Services;
      6.   using System.Web.Services.Protocols;

                                                       24
7. using System.Collections;
8.
9. [ WebService( Namespace = "http://www.deitel.com/", Description=
10. "A Web service that deals and counts cards for the game Blackjack" ) ]
11. [ WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 ) ]
12. public class BlackjackService : System.Web.Services.WebService
13. {
14. // deals card that has not yet been dealt
15. [ WebMethod( EnableSession=true,
16.      Description="Deal a new card from the deck." ) ]
17. public string DealCard()
18. {
19.      string card = "2 2";
20.
21.      // get client's deck
22.      ArrayList deck = ( ArrayList )( Session[ "deck" ] );
23.      card = Convert.ToString( deck[ 0 ] );
24.      deck.RemoveAt( 0 );
25.      return card;
26. } // end method DealCard
27.
28. // creates and shuffles a deck of cards
29. [ WebMethod( EnableSession=true,
30.      Description="Create and shuffle a deck of cards." ) ]
31. public void Shuffle()
32. {
33.      object temporary; // holds card temporarily during swapping
34.      Random randomObject = new Random(); // generates random numbers
35.      int newIndex; // index of randomly selected card
36.      ArrayList deck = new ArrayList(); // stores deck of cards (strings)
37.
38.      // generate all possible cards
39.      for ( int i = 1; i <= 13; i++ ) // loop through face values
40.         for ( int j = 0; j <= 3; j++ ) // loop through suits
41.            deck.Add( i + " " + j ); // add card (string) to deck
42.
43. // shuffles deck by swapping each card with another card randomly
44.      for ( int i = 0; i < deck.Count; i++ )
45.      {
46.         // get random index
47.         newIndex = randomObject.Next( deck.Count - 1 );
48.         temporary = deck[ i ]; // save current card in temporary variable
49.         deck[ i ] = deck[ newIndex ]; // copy randomly selected card
50.         deck[ newIndex ] = temporary; // copy current card back into deck
51.      } // end for

                                          25
52.
53.       // add this deck to user's session state
54.       Session.Add( "deck", deck );
55.    } // end method Shuffle
56.
57.   // computes value of hand
58.     [ WebMethod( Description=
59.       "Compute a numerical value for the current hand." ) ]
60.     public int GetHandValue( string dealt )
61.     {
62.       // split string containing all cards
63.       char[] tab = { '\t' };
64.       string[] cards = dealt.Split( tab ); // get array of cards
65.       int total = 0; // total value of cards in hand
66.       int face; // face of the current card
67.       int aceCount = 0; // number of aces in hand
68.
69.   // loop through the cards in the hand
70.        foreach ( string drawn in cards )
71.        {
72.          // get face of card
73.          face = Int32.Parse( drawn.Substring( 0, drawn.IndexOf( " " ) ) );
74.
75.         switch ( face )
76.         {
77.            case 1: // if ace, increment aceCount
78.              aceCount++;
79.              break;
80.            case 11: // if jack add 10
81.            case 12: // if queen add 10
82.            case 13: // if king add 10
83.              total += 10;
84.              break;
85.            default: // otherwise, add value of face
86.              total += face;
87.              break;
88.         } // end switch
89.      } // end foreach
90.
91.      // if there are any aces, calculate optimum total
92.      if ( aceCount > 0 )
93.      {
94.         // if it is possible to count one ace as 11, and the rest
95.         // as 1 each, do so; otherwise, count all aces as 1 each
96.         if ( total + 11 + aceCount - 1 <= 21 )

                                                 26
     97.          total += 11 + aceCount - 1;
     98.        else
     99.          total += aceCount;
     100.         } // end if
     101.
     102.      return total;
     103.       } // end method GetHandValue
     104.    } // end class BlackjackService

   Lines 15-16 define method DealCard as a Web method. Setting property EnableSession to true
    indicates that session information should be maintained and should be accessible to this method. This is
    required only for methods that must access the session information. Doing so allows the Web service to
    use HttpSessionState object (named Session by ASP.NET) to maintain the deck of the cards for each
    client application that uses the Web service (line 22). We can use Session to store objects for a specific
    client between method calls. Method DealCard removes a card from the deck and sends it to the client.
    Without using a session variable, the deck of cards would need to be passed back and forth with each
    method call. Using Session state make the method easy to call (it requires no arguments), and avoids the
    overhead of sending the deck over the network multiple times.
   At this point, our Web service contains methods that use session variables. However, the Web service still
    cannot determine which session variables belong to which user. If two clients successfully call the
    DealCard method, the same deck would be manipulated. To avoid this problem, the Web service
    automatically creates a cookie to uniquely identify each client.
   A Web browser client that has cookie handling enabled stores cookies automatically. A non-browser client
    application that consumes this Web service must create a CookieContainer object to store cookies sent
    from the server.
   Web method DealCard (lines 15-26) selects a card from the deck and sends it to the client. The method
    first obtains the current user’s deck as an ArrayList from the Web service’s Session object (line 22).
    After obtaining the user’s deck, DealCard removes the top card from the deck (line 24) and returns the
    card’s value as a string (line 25).
   Method Shuffle (lines 29-55) generates an ArrayList representing a deck of cards, shuffles it and stores
    the shuffled cards in the client’s Session object.
   Lines 39-41 use nested for statement to generates strings in the form “face suit” to represent each possible
    card in a deck.
   Lines 44-51 shuffle the deck by swapping each card with another card selected at random. Line 54 adds
    the ArrayList to the Session object to maintain the deck between method calls from a particular client.
   Method GetHandValue (lines 58-103) determines the total value of the cards in a hand by trying to attain
    the highest score possible without going over 21. Recall that an ace can be counted as either 1 or 11, and
    all face cards count as 10. The client application maintains a hand of cards as a string in which each card
    is separated by a tab character. Line 64 tokenizes the hand of cards (represented by dealt) into individual
    cards by calling string method Split and passing to it any array that contains the delimiter characters (in
    this case, just a tab). Split uses the delimiter characters to separate tokens in the string. Lines 70-89 count
    the value of each card. Line 73 retrieves the first integer – the face – and uses that value in the switch
    statement (lines 75-88). If the card is an ace, the method increments variable aceCount. If the card is an
    11, 12 or 13 (jack, queen or king), the method adds 10 to the total value of the hand (line 86).
   Because an ace can have either of two values, additional logic is required to process hand contains several

                                                       27
     aces, only one ace can be counted as 11 (if two aces each are counted as 11, the hand would have a losing
     value of 22). The condition in line 96 determines whether counting one as 11 and the rest as 1 will result
     in a total that does not exceed 21. if this is possible, line 97 adjusts the total accordingly. Otherwise, line
     99 adjusts the total, counting each ace as 1.
    Method GetHandValue maximizes the value of the current cards without exceeding 21. imagine, for
     example, that the dealer has a 7 and receives an ace. The new total could be either 8 or 18. however,
     GetHandValue always maximizes the value of the cards without going over 21, so the new total is 18.

Consuming the Blackjack Web Service
  Now we use the blackjack Web service in a Windows application. This application uses an instance of
    BlackjackService (declared in line 18 and created in line 47) to represent the dealer. The Web service
    keeps track of the player’s and the dealer’s cards (i.e., all the cards that have been dealt).
         1. // Blackjack.cs
         2. // Blackjack game that uses the Blackjack Web service.
         3. using System;
         4. using System.Collections.Generic;
         5. using System.ComponentModel;
         6. using System.Data;
         7. using System.Drawing;
         8. using System.Text;
         9. using System.Windows.Forms;
         10. using System.Net;
         11. using System.Collections;
         12.
         13. namespace Blackjack
         14. {
         15. public partial class BlackjackForm : Form
         16. {
         17.     // reference to Web service
         18.     private localhost.BlackjackService dealer;
         19.
         20.     // string representing the dealer's cards
         21.     private string dealersCards;
         22.
         23.     // string representing the player's cards
         24.     private string playersCards;
         25.     private ArrayList cardBoxes; // list of PictureBoxes for card images
         26.     private int currentPlayerCard; // player's current card number
         27.     private int currentDealerCard; // dealer's current card number
         28.
         29. // enum representing the possible game outcomes
         30.     public enum GameStatus
         31.     {
         32.        PUSH, // game ends in a tie
         33.        LOSE, // player loses

                                                        28
34.        WIN, // player wins
35.        BLACKJACK // player has blackjack
36.     } // end enum GameStatus
37.
38.     public BlackjackForm()
39.     {
40.        InitializeComponent();
41.     } // end constructor
42.
43. // sets up the game
44.     private void BlackjackForm_Load( object sender, EventArgs e )
45.     {
46.        // instantiate object allowing communication with Web service
47.        dealer = new localhost.BlackjackService();
48.
49.        // allow session state
50.        dealer.CookieContainer = new CookieContainer();
51.        cardBoxes = new ArrayList();
52.
53.        // put PictureBoxes into cardBoxes
54.        cardBoxes.Add( pictureBox1 );
55.        cardBoxes.Add( pictureBox2 );
56.        cardBoxes.Add( pictureBox3 );
57.        cardBoxes.Add( pictureBox4 );
58.        cardBoxes.Add( pictureBox5 );
59.       cardBoxes.Add( pictureBox6 );
60.        cardBoxes.Add( pictureBox7 );
61.        cardBoxes.Add( pictureBox8 );
62.        cardBoxes.Add( pictureBox9 );
63.        cardBoxes.Add( pictureBox10 );
64.        cardBoxes.Add( pictureBox11 );
65.        cardBoxes.Add( pictureBox12 );
66.        cardBoxes.Add( pictureBox13 );
67.        cardBoxes.Add( pictureBox14 );
68.        cardBoxes.Add( pictureBox15 );
69.        cardBoxes.Add( pictureBox16 );
70.        cardBoxes.Add( pictureBox17 );
71.        cardBoxes.Add( pictureBox18 );
72.        cardBoxes.Add( pictureBox19 );
73.        cardBoxes.Add( pictureBox20 );
74.        cardBoxes.Add( pictureBox21 );
75. cardBoxes.Add( pictureBox22 );
76.     } // end method BlackjackForm_Load
77.
78.     // deals cards to dealer while dealer's total is less than 17,

                                        29
79.    // then computes value of each hand and determines winner
80.    private void DealerPlay()
81.    {
82.       // while value of dealer's hand is below 17,
83.       // dealer must take cards
84.       while ( dealer.GetHandValue( dealersCards ) < 17 )
85.       {
86.          dealersCards += '\t' + dealer.DealCard(); // deal new card
87.
88.        // update GUI to show new card
89.        DisplayCard( currentDealerCard, "" );
90.        currentDealerCard++;
91.         MessageBox.Show( "Dealer takes a card" );
92.     } // end while
93.
94.     int dealersTotal = dealer.GetHandValue( dealersCards );
95.     int playersTotal = dealer.GetHandValue( playersCards );
96.
97.     // if dealer busted, player wins
98.     if ( dealersTotal > 21 )
99.     {
100.               GameOver( GameStatus.WIN );
101.               return;
102.            } // end if
103.
104.             // if dealer and player have not exceeded 21,
105.             // higher score wins; equal scores is a push.
106.            if ( dealersTotal > playersTotal )
107.                GameOver( GameStatus.LOSE );
108.             else if ( playersTotal > dealersTotal )
109.                GameOver( GameStatus.WIN );
110.             else
111.                GameOver( GameStatus.PUSH );
112.          } // end method DealerPlay
113.
114.          // displays card represented by cardValue in specified PictureBox
115.          public void DisplayCard( int card, string cardValue )
116.          {
117.             // retrieve appropriate PictureBox from ArrayList
118.             PictureBox displayBox = ( PictureBox )( cardBoxes[ card ] );
119.
120.            // if string representing card is empty,
121.           // set displayBox to display back of card
122.            if ( cardValue == "" )
123.            {

                                         30
124.        displayBox.Image =
125.          Image.FromFile( "blackjack_images/cardback.png" );
126.        return;
127.     } // end if
128.
129.     // retrieve face value of card from cardValue
130.     string face = cardValue.Substring( 0, cardValue.IndexOf( " " ) );
131.
132.     // retrieve the suit of the card from cardValue
133.     string suit =
134.        cardValue.Substring( cardValue.IndexOf( " " ) + 1 );
135.
136.     char suitLetter; // suit letter used to form image file name
137.
138.    // determine the suit letter of the card
139.     switch ( Convert.ToInt32( suit ) )
140.     {
141.        case 0: // clubs
142.          suitLetter = 'c';
143.          break;
144.        case 1: // diamonds
145.          suitLetter = 'd';
146.           break;
147.        case 2: // hearts
148.          suitLetter = 'h';
149.          break;
150.        default: // spades
151.          suitLetter = 's';
152.          break;
153.     } // end switch
154.
155.     // set displayBox to display appropriate image
156.      displayBox.Image = Image.FromFile(
157.         "blackjack_images/" + face + suitLetter + ".png" );
158.   } // end method DisplayCard
159.
160.   // displays all player cards and shows
161.   // appropriate game status message
162.   public void GameOver( GameStatus winner )
163.   {
164.      char[] tab = { '\t' };
165.      string[] cards = dealersCards.Split( tab );
166.
167.     // display all the dealer's cards
168.     for ( int i = 0; i < cards.Length; i++ )

                                    31
169.       DisplayCard( i, cards[ i ] );
170.
171.    // display appropriate status image
172.    if ( winner == GameStatus.PUSH ) // push
173.       statusPictureBox.Image =
174.          Image.FromFile( "blackjack_images/tie.png" );
175.    else if ( winner == GameStatus.LOSE ) // player loses
176.       statusPictureBox.Image =
177.          Image.FromFile( "blackjack_images/lose.png" );
178.    else if ( winner == GameStatus.BLACKJACK )
179.       // player has blackjack
180.       statusPictureBox.Image =
181.          Image.FromFile( "blackjack_images/blackjack.png" );
182.    else // player wins
183.       statusPictureBox.Image =
184.          Image.FromFile( "blackjack_images/win.png" );
185.
186.    // display final totals for dealer and player
187.    dealerTotalLabel.Text =
188.       "Dealer: " + dealer.GetHandValue( dealersCards );
189.    playerTotalLabel.Text =
190.       "Player: " + dealer.GetHandValue( playersCards );
191.
192.      // reset controls for new game
193.      stayButton.Enabled = false;
194.      hitButton.Enabled = false;
195.      dealButton.Enabled = true;
196.   } // end method GameOver
197.
198.   // deal two cards each to dealer and player
199.   private void dealButton_Click( object sender, EventArgs e )
200.   {
201.      string card; // stores a card temporarily until added to a hand
202.
203.    // clear card images
204.     foreach ( PictureBox cardImage in cardBoxes )
205.        cardImage.Image = null;
206.
207.    statusPictureBox.Image = null; // clear status image
208.    dealerTotalLabel.Text = ""; // clear final total for dealer
209.    playerTotalLabel.Text = ""; // clear final total for player
210.
211.    // create a new, shuffled deck on the remote machine
212.    dealer.Shuffle();
213.

                                   32
214.    // deal two cards to player
215.    playersCards = dealer.DealCard(); // deal a card to player's hand
216.
217.     // update GUI to display new card
218.     DisplayCard( 11, playersCards );
219.    card = dealer.DealCard(); // deal a second card
220.     DisplayCard( 12, card ); // update GUI to display new card
221.     playersCards += '\t' + card; // add second card to player's hand
222.
223.    // deal two cards to dealer, only display face of first card
224.    dealersCards = dealer.DealCard(); // deal a card to dealer's hand
225.    DisplayCard( 0, dealersCards ); // update GUI to display new card
226.    card = dealer.DealCard(); // deal a second card
227.    DisplayCard( 1, "" ); // update GUI to show face-down card
228.    dealersCards += '\t' + card; // add second card to dealer's hand
229.
230.    stayButton.Enabled = true; // allow player to stay
231.    hitButton.Enabled = true; // allow player to hit
232.    dealButton.Enabled = false; // disable Deal Button
233.
234.    // determine the value of the two hands
235.    int dealersTotal = dealer.GetHandValue( dealersCards );
236.    int playersTotal = dealer.GetHandValue( playersCards );
237.
238.    // if hands equal 21, it is a push
239.    if ( dealersTotal == playersTotal && dealersTotal == 21 )
240.       GameOver( GameStatus.PUSH );
241.    else if ( dealersTotal == 21 ) // if dealer has 21, dealer wins
242.       GameOver( GameStatus.LOSE );
243.    else if ( playersTotal == 21 ) // player has blackjack
244.       GameOver( GameStatus.BLACKJACK );
245.
246.    // next dealer card has index 2 in cardBoxes
247.    currentDealerCard = 2;
248.
249.      // next player card has index 13 in cardBoxes
250.      currentPlayerCard = 13;
251.   } // end method dealButton
252.
253.   // deal another card to player
254.   private void hitButton_Click( object sender, EventArgs e )
255.   {
256.      // get player another card
257.      string card = dealer.DealCard(); // deal new card
258.      playersCards += '\t' + card; // add new card to player's hand

                                 33
259.
260.         // update GUI to show new card
261.         DisplayCard( currentPlayerCard, card );
262.         currentPlayerCard++;
263.
264.         // determine the value of the player's hand
265.         int total = dealer.GetHandValue( playersCards );
266.
267.        // if player exceeds 21, house wins
268.        if ( total > 21 )
269.        GameOver( GameStatus.LOSE );
270.
271.          // if player has 21,
272.          // they cannot take more cards, and dealer plays
273.          if ( total == 21 )
274.          {
275.             hitButton.Enabled = false;
276.             DealerPlay();
277.          } // end if
278.       } // end method hitButton_Click
279.
280.         // play the dealer's hand after the play chooses to stay
281.         private void stayButton_Click( object sender, EventArgs e )
282.         {
283.            stayButton.Enabled = false; // disable Stay Button
284.            hitButton.Enabled = false; // display Hit Button
285.      dealButton.Enabled = true; // re-enable Deal Button
286.            DealerPlay(); // player chose to stay, so play the dealer's hand
287.         } // end method stayButton_Click
288.      } // end class BlackjackForm
289.   } // end namespace Blackjack




                                      34

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:0
posted:11/16/2013
language:Latin
pages:34
 wuzhenguang wuzhenguang
About