18.2. Building an XML Web Service

 < Day Day Up > 

In this section, we demonstrate how to build a Web Service by hand and then access it using a browser. We also show how to create the same Web Service using Visual Studio.NET. Although IIS is used, the examples run on any Web server.

Creating a Web Service by Hand

The first step is to select or create a virtual directory under IIS that will hold the Web Service source code file(s). Any physical directory can be mapped to an IIS virtual directory. You can use the Internet Service Manager or simply right-click the directory and select Sharing-Web Sharing. Then, assign it an alias that will be used in its URL. In our example, we will place the service in the \ws subdirectory.

After the directory has been set up, the next step is to use a text editor to create a file in this directory with the .asmx extension to contain the Web Service code. Listing 18-1 contains the code for our simple Web Service. This service exposes a method GetdayBorn that accepts three integer parameters that represent the month, day, and year for birth date. A string value containing the day of the week (Monday, Tuesday, and so on) for this date is returned. The service performs rudimentary error checking and returns an error message if the date is invalid.

Listing 18-1. Web Service to Return a Date's Day of Week BirthDayWS.asmx
 <%@ WebService Language="C#"  %> using System; namespace BirthDayWS {    public class BirthDay    {       [System.Web.Services.WebMethod       (Description="Return day of week for a date")]       public string GetDayBorn(int mo, int day, int yr)       {          bool err = false;          string dob;          if (mo <1 || mo >12) err=true;          if (day < 1 || day > 31) err=true;          if (err)             dob = "Invalid Date";          } else {             DateTime dt = new DateTime(yr,mo,day);             dob = dt.ToString("dddd"); // Get day          }          return(dob);       }    } } 

The code consists of a single class and a method that is invoked by a client to return the day-of-week value. In addition to the C# code that implements the logic of the service, two other elements are required: a WebService directive and a WebMethod attribute.

WebService Directive

The WebService directive identifies the file as defining a Web Service:

 <%@ WebService Language="C#"  %> 

The directive specifies the class implementing the XML Web Service and the programming language used in the implementation. In this example, the directive and the code for the class are present in the BirthDayWS.asmx file. Note, however, that the class can be in a separate assembly. In that case, the separate assembly is placed in a \bin directory below the Web application where the Web Service resides. If the class were in bdAssembly.dll, the WebService directive would look like this:

 <%@ WebService Language="C#"        %> 

This statement would be the only line needed in the .asmx file.

WebMethod Attribute

The WebMethod attribute identifies a method as being accessible to clients making HTTP requests that is, as an XML Web Service. Although not required, it is a good practice to include the Description property to describe the purpose of the method:

 [System.Web.Services.WebMethod        (Description="Return day of week for a date")] 

The description is added to the WSDL for the service and as we will see next is displayed when a Web Service is accessed via a browser. The WebMethod attribute has other optional parameters, which are described later in this chapter.

Testing the Web Service

A quick way to test the newly developed Web Service is to point a browser to its location. For this example, we enter the address:

 http://localhost/ws/BirthDayWS.asmx 

This brings up a Web page that lists all the services (methods) available through this .asmx file as well as a Service Description link that displays WSDL information. For our example, there is only one method, GetdayBorn. Clicking it yields the page shown in Figure 18-3. This page contains the name of the class implementing the Web Service, the name of the method to be invoked, a description of the method, and text boxes for entering values to be passed to the Web Service method.

Figure 18-3. Using a browser to access the BirthDay Web Service


To use the Web Service, fill in the parameter values and select the Invoke button. This causes the parameters to be sent to the Web Service using the HTTP POST protocol. The output received from the service is an XML document shown in Figure 18-4.

Figure 18-4. BirthDayWS output


The output from the method is included in the string element of the XML wrapper. Fortunately, we do not have to parse the XML to retrieve this value when writing our own SOAP client. The WSDL contract provides information that allows our client to treat the remote Web Service as a method that returns data conforming to the method's type not as XML.

Core Note

It is unnecessary to compile the .asmx file containing the Web Service in order to deploy it. On a Microsoft Windows server, the ASP.NET runtime automatically compiles the file the first time it is requested and places it in a subdirectory named after the virtual directory on the following path:

 <%windir%>\Microsoft.NET\Framework\<version>\ Temporary ASP.NET Files\ 


To view the WSDL associated with this Web Service, open your browser and append ?WSDL to the URL of the .asmx file:

 http://localhost/ws/BirthDayWS.asmx?WSDL 

Creating a Web Service Using VS.NET

Aside from the usual advantages of IntelliSense and single key compilation (F5), the major advantage of VS.NET over a manual approach is that it automatically creates a new virtual directory under IIS to host the Web Service. This directory takes the same name as the project.

To create a Web Service with VS.NET, open it up and select ASP.NET Web Service as the project type. Assign it a project name (BirthDayWS, in this case) that reflects the purpose of the Web Service. When the project opens, select View Code and you will find that the following template class is predefined:

 namespace BirthDayWS {    public class Service1 : System.Web.Services.WebService    {       public Service1()       { InitializeComponent(); }       private IContainer components = null;       private void InitializeComponent()   {   }       protected override void Dispose( bool disposing )       {          if(disposing && components != null)          {             components.Dispose();          }          base.Dispose(disposing);       }          // --> Place BirthDayWS code here    } } 

To implement the service, rename the class to Birthday and add the code for the GeTDayBorn method. Use the browser to test the service by either compiling the code, which automatically invokes the browser, or directly pointing the browser to

 http://localhost/BirthDayWS/BirthDayWS.asmx 

The only significant difference between this code and our handcrafted version is that the Web class now inherits from WebService rather than the default System.Object. The service works either way, but by inheriting from WebService it gains the functionality of an ASP.NET application.

System.Web.Services.WebService Class

The WebService base class exposes properties to a Web Service that enable it to access the intrinsic ASP.NET objects introduced in Chapter 17, "The ASP.NET Application Environment."

  • Application. Provides access to an Application object that can be used to maintain state information for all sessions accessing the Web Service. For example, it can be used to keep track of how many times the service is called.

  • Session. Provides access to the HttpSessionState object that maintains session state information. It can be used, for example, to track how many times a service is called while the current session is alive. This property is available only if the EnableSession property of the WebMethodAttribute is set to true.

  • Context. Exposes the HttpContext class. Recall that this class provides a wealth of information about the current request.

  • User. Returns the IPrincipal object that provides user authentication information and can be used to determine whether the request is authorized (see Chapter 17).

To demonstrate the use of state information, let's extend our example to use the Application object to keep track of the number of times the Web Service is called.

Our first step is to add the statement in bold to the GeTDayBorn method:

 dob = dt.ToString("dddd"); // extracts day this.Application["count"] = GetCount()+1; 

Next, add a method to the class that internally returns the "count" value of the Application object. Finally, add a method, GetVisitors, which allows clients to view the number of calls to the Web Service as a Web Service call:

 private int GetCount() {    object ob = this.Application["count"];    if (ob == null) {       return(0);    } else {       return((int)ob);    } } [WebMethod(Description="Number of times Web Service called.")] public int GetVisitors() {    return (GetCount()); } 

Extending the Web Service with the WebService and WebMethod Attributes

The BirthDayWS example demonstrates that a functioning Web Service can be created with a minimal use of .NET classes. However, before releasing a Web Service to the Internet, there are additional features that should be considered. For instance, each XML Web Service should be given a unique namespace rather than relying on the default <http://tempuria.org>, caching can be implemented to improve performance, and overloaded methods can be implemented using the WebMethod attribute.

The WebService Attribute

The optional WebService attribute (not to be confused with the WebService directive) is applied to the class implementing the XML Web Service. It has two useful properties: Description, which describes the overall Web Service, and Namespace, which sets the default XML namespace for the service. In general terms, namespaces are used to avoid naming conflicts among XML elements and attributes. In this case, it is used to make the Web Service name unique.

Let's add a WebService attribute containing a namespace and description to the class in our BirthDayWS example:

 [WebService(Namespace="http://www.dateservices.com/ws/",    Description="<b>Web Service that Provides Date    Functions.</b>")] public class BirthDay : System.Web.Services.WebService 

It is important to note that the namespace is intended to be a unique identifier, and does not need to actually point to anything. Domains are typically used to take advantage of their uniqueness.

Figure 18-5 shows the page that is returned when we call the Web Service that is now updated with the WebService attribute and the GetVisitors method.

Figure 18-5. Updated BirthDayWS Web Service


The WebMethod Attribute

As mentioned previously, the WebMethod attribute is required to expose a method as part of a Web Service. Its properties include Description, which we have already used, EnableSession, MessageName, CacheDuration, and TRansactionOption. The latter property applies to applications that call transactional COM+ components a topic not discussed in this book. The other three properties are useful for developing general Web Services. Let's look at the role of each.

EnableSession: Activate the Use of Session State Information

This property is used with Web Services that inherit from the WebService class. Turning it on allows a Web Service method to access session information through WebService.Session or HttpContext.Current.Session. By default, this is set to false, because maintaining session data increases memory consumption and reduces performance.

 Example: [WebMethod(EnableSession=true)]   // Default is false 

Be aware that Windows Forms clients do not provide the same support for session state variables that a browser does. Sessions rely on cookies to preserve state data. Unlike browsers, Windows Forms applications do not store cookies. Thus, the service thinks that each request is the first request. There is a work-around, however, which is described in the following section on building a Web Services client.

MessageName: Create Overloaded Web Operations

Suppose we want to add a method to our Web Service that accepts the month as a string rather than an integer. Because the signature is different than the original GeTDayBorn method, we can give it the same method name and C# will compile it as an overloaded method. However, when we try to access it from a browser, we receive a system exception indicating that the two methods have the same name.

The problem lies in the WSDL, which requires that each Web method in its XML elements be uniquely named, irrespective of its signature. By default, the routine in ASP.NET that generates WSDL code uses the name for both. The solution aside from renaming the method is to use the MessageName property to indicate a surrogate name.

 [WebMethod(Description="Return day of week for any date",        MessageName="GetDayBorn2")] public string GetDayBorn(string month, int day, int yr){    // Code to convert string month to int value    string allMos= "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";    month = month.Substring(0,3).ToUpper();    int ndx = allMos.IndexOf(month);    if(ndx <0) err=true; else mo = ndx/3 +1;    // Remainder of code goes here... 

CacheDuration: Caching Output from a Web Operation

Just like ASP.NET Web pages, output from a Web method can be cached to obviate executing it each time the method is called. The CacheDuration property specifies how long (in seconds) the output is to be cached. For methods that accept arguments, cached output is saved for each unique set of arguments.

 Example: [WebMethod(CacheDuration=1800)]   // Value is in seconds 

The only rule to follow when (if) setting up caching is to do it judiciously. Caching greatly improves performance for methods that are requested frequently and implement logic that requires lengthy processing. On the other hand, methods such as GetdayBorn in our example can actually hurt performance because most requests to it will yield unique results.

Using web.config to Configure Web Service Options

.NET Web Services support four protocols: HttpGet, HttpPost, HttpSoap, and HttpLocalHost. Of these, HttpPost and HttpGet are disabled for security reasons. The effect of this is to limit Web Service access to URLs located on http://localhost; an attempt by a remote machine to access a local Web Service results in this message being displayed:

 The test form is only available for requests from the local machine 

To make a Web Service available to remote users, it is necessary to enable the HttpPost and HttpGet protocols. This is easily done by configuring the <protocol> section of the web.config file to "add" the two protocols.

 <system.web>    <webServices>       <protocols>          <add name="HttpGet"/>          <add name="HttpPost"/>       </protocols>    </webServices> </system.web> 

Recall that navigating to a Web Services page with no parameters brings up a help page that describes how to use the service, and provides links to invoke the Web Service methods or display the WSDL. If you do not want to expose this information, you can disable the display of help pages by removing the Documentation protocol. To do so, place the following statement in the <protocols> element of the web.config file:

 <remove name="Documentation" /> 

     < Day Day Up > 


    Core C# and  .NET
    Core C# and .NET
    ISBN: 131472275
    EAN: N/A
    Year: 2005
    Pages: 219

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