![]() |
< Day Day Up > |
![]() |
18.2. Building an XML Web ServiceIn 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 HandThe 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?tt>BirthDayWS.asmx<%@ WebService Language="C#" Class="BirthDayWS.BirthDay" %> 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 DirectiveThe WebService directive identifies the file as defining a Web Service: <%@ WebService Language="C#" Class="BirthDayWS.BirthDay" %> 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#" Class="BirthDayWS.BirthDay, bdAssembly" %> This statement would be the only line needed in the .asmx file. WebMethod AttributeThe WebMethod attribute identifies a method as being accessible to clients making HTTP requests梩hat 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梐s we will see next梚s 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 ServiceA 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梟ot as XML. Core Note
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.NETAside 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 ClassThe 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."
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 AttributesThe 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 AttributeThe 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 ServiceThe WebMethod AttributeAs 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梐 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 InformationThis 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 OperationsSuppose 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梐side from renaming the method梚s 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 OperationJust 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 > |
![]() |