ASP.NET Web Services

The Internet is evolving from a collection of isolated Web sites and applications into a general communication bus for distributed applications. Recall from Chapter 1 that Microsoft and many other companies believe that the components of the distributed applications will communicate with each other using Web services. A Web service (more specifically, XML Web service) is a service that can be programmatically accessed over the Web. It is based on industry standards such as SOAP and WSDL.

ASP.NET makes it easy to create and test Web services.

Providing Web Services

Let's define a simple Web service class that defines a method to add two numbers. Here is the code:

<%@ WebService Language="C#" Class="MyCompany.MyCalculator" %>

// Calculator.asmx – Project Calculator

using System.Web.Services;

namespace MyCompany {

     [WebService(Namespace="http://localhost/WSRemoting/")]
     public class MyCalculator : WebService {

       [WebMethod]
       public int Add(int a, int b) {
         return (a+b);
       }
     }
}

Under ASP.NET, a Web service source file is saved with the extension .asmx. The first line of the source file contains a directive for ASP.NET. The Language attribute specifies the programming language being used for the code and the Class attribute specifies the name of the class that should be published as a Web service.

The rest of the source defines the code for the MyCompany.MyCalculator Web service.

It is also possible, and recommended, to keep the code in a separate file. In this case the code must be compiled and the generated assembly must be placed in a subdirectory named Bin. The name of the generated assembly does not matter. ASP.NET scans all the assemblies in the Bin directory looking for the class specified in the Class attribute.

If you use the Visual Studio .NET Wizard to generate the Web service, the wizard creates a file, Service.asmx, to store the WebService directive and another file Service.asmx.cs (or .vb for Visual Basic) to store the code, where Service is the name of your service. Using Visual Studio .NET to generate a Web service is a good idea. The wizard also creates a virtual directory under IIS and configures it to allow program execution. However, if you already have an existing IIS virtual directory that you wish to use, you can select the project template called New Project in Existing Folder to create your Web service project.

CodeBehind Attribute

A Visual Studio.NET Web service project automatically adds an attribute CodeBehind to the WebService directive. This attribute is not used by ASP.NET. Visual Studio .NET uses it to associate an .asmx file with a source file (.cs or .vb).


A Web service class is typically inherited from a standard class WebService (namespace System.Web.Services). This makes it possible to directly access certain ASP.NET intrinsic objects such as those for application and session state. By default, Web service classes created using Visual Studio .NET inherit from the WebService class.

It is not a requirement for your Web service class to inherit from WebService. Your class can still access the ASP.NET intrinsic objects from a static property, System.Web.HttpContext.Current.

Whether or not your Web service inherits from WebService, there are a few requirements your class must meet.

First, the class must be marked as public and must have a public default constructor. This makes it possible for ASP.NET to create an instance of your Web service class.

Second, and more important, your class must support MBV semantics, not MBR. ASP.NET Web services are about loosely coupled systems. MBR objects provide for distributed identity and are not supported under ASP.NET. For the same reason, MBR objects should not be returned from ASP.NET Web services.

Finally, each method that should be exposed as part of the service must be attributed with the [WebMethodAttribute] token, as shown in the earlier code. The WebMethodAttribute attribute contains several properties for configuring the behavior of the method. For example, you can add a brief description of your Web service method, or you can enable or disable the ASP.NET session state for the method. Check the SDK documentation for a complete list of supported properties.

The simple datatypes that a Web method can support can be found in the section Built-In Datatypes of the XML Schema Part 2: Datatypes specifications (www.w3.org/TR/xmlschema-2/). Examples include int, float, string, and so on. Web methods also support compound types such as structures and array for method parameters as well as the return value. Check the World Wide Web Consortium (W3C) site for more details (www.w3.org/TR/SOAP/#_Toc478383532).

A Web service class can optionally be marked with the WebServiceAttribute attribute. This lets you add extra information to your Web service, such as the description of the service and the namespace the Web service belongs to. A Web service's namespace is not the same as assembly namespaces that you have been used to seeing, although the concept is the same—to resolve naming conflicts. A Web service namespace is identified by a URI. If not specified, the default namespace is http://tempuri.org/.

Let's test this little program of ours. First, create a virtual directory under IIS. In my case, the alias for the virtual directory is WSRemoting and the root directory for this alias is D:DotNetProgrammingCh06-DistributedComputingCalculator. This is where the file Calculator.asmx is stored.

No explicit compilation is needed to run the Web service. Behind the scenes, when a call is made on the Web service, ASP.NET automatically compiles the code and generates a .NET assembly. Subsequently, ASP.NET continues to monitor the source files and recompiles the code if it detects a change in the files.

ASP.NET Web Services versus .NET Remoting

In the previous section, we saw that the .NET remoting framework is capable of providing services over an HTTP channel, which by default uses the SOAP formatter. The server application can also produce WSDL-compliant XML schema. This makes you wonder why there is any need for a different technology to create Web services.

Although it is true that both ASP.NET and .NET remoting can serialize objects in SOAP format, the two serialization mechanisms have entirely different goals. The goal of the SOAP formatter under .NET remoting is to serialize any .NET object with true fidelity. You can change the formatter from binary to SOAP and the chances are your managed code will not break. The goal of the ASP.NET serializer is to provide interoperability across various development platforms. It does not necessarily support everything in the common language runtime.

Another subtle difference is that ASP.NET uses XMLSerializer (Chapter 5) for serializing objects. This class serializes only the public fields of a class. Contrast this to the SOAP formatter used by .NET remoting—it serializes the public as well as the private fields (to maintain true fidelity).

If you know that the server and all its clients are running the common language runtime on their systems, then there is nothing wrong with using .NET remoting. Perhaps this should be your choice. Not only do you get full fidelity for the .NET objects but you can also get performance improvement by using the binary formatter. Plus, you get a choice of TCP, HTTP, or any other proprietary channel.

It may be a while before the common language runtime will be available on all systems. In fact, it may never be available on some platforms. Therefore, if interoperability is your concern, then you should use the ASP.NET Web services architecture.


ASP.NET also takes care of generating the WSDL definition for the class. From Microsoft Internet Explorer, for example, if you type http://localhost/WSRemoting/Calculator.asmx?wsdl (note ?wsdl at the end), then you will see the WSDL definition being displayed.

There is much more. Entering http://localhost/WSRemoting/Calculator.asmx?disco in Internet Explorer, causes ASP.NET to automatically produce the discovery document. A discovery document provides clients with information on available Web services and their descriptions. Discovery documents are typically stored in .disco files.

Finally, ASP.NET also makes it easy to test a Web service. For example, from Internet Explorer, if you type http://localhost/WSRemoting/Calculator.asmx, the resulting Web page shows the methods that are available in the Web service. When you click on a method, ASP.NET automatically generates a page that you can use for testing the method. A snapshot of the test page is shown in Figure 6.8.

Figure 6.8. A snapshot of an ASP.NET generated test page.


Consuming Web Services

The NET SDK ships with a tool called the Web Services Description Language tool (wsdl.exe) that can be used to generate a proxy class for a Web service. The proxy class defines all the methods that are exposed as part of the Web service. A client can simply invoke these methods, which in turn communicate with the Web service over the network. The proxy takes care of generating the appropriate SOAP messages and converting the resulting SOAP responses to the common language runtime types.

The following command line generates the proxy class for MyCalculator Web service. The code is saved in file Proxy.cs:

wsdl.exe -o:Proxy.cs 
     http://localhost/WSRemoting/Calculator.asmx?wsdl

By default, the code is generated in C# but a different programming language can be specified by means of a command-line switch.

Here is the code excerpt for the generated proxy class:

public class MyCalculator :
     System.Web.Services.Protocols.SoapHttpClientProtocol {
     public MyCalculator() {
       this.Url =
         "http://localhost/WSRemoting/Calculator.asmx";
     }

     public int Add(int a, int b) {
       ...
     }
}

Note that the proxy class inherits from a class SoapHttpClientProtocol. This class provides some frequently used properties when dealing with Wsdl.exe-generated proxies. For example, you can specify security credentials for Web service client authentication (we will see this in Chapter 9). If the client is behind a firewall, you can also specify the proxy server to use, as illustrated in the following client-side code:

MyCalculator calc = new MyCalculator();
calc.Proxy =
  new System.Net.WebProxy("http://myproxyserver:8080");

Note the code in the constructor of the generated MyCalculator class. By default, the proxy class points to the URL of the Web service that was used to generate the proxy class. However, it is possible to point to a different URL at runtime by setting the URL property of the SoapHttpClientProtocol class as shown here:

calc.Url = "http://Machine/Alias/File.asmx";

Here is our actual client code:

// Project Calculator/MyClient

// File MyClient.cs
class MyClient {
     public static void Main() {
       MyCalculator calc = new MyCalculator();
       int retVal = calc.Add(10, 20);
       Console.WriteLine(retVal);
     }
}

Compile the client code as follows:

csc -out:MyClient.exe MyClient.cs Proxy.cs

When MyClient.exe is executed, it calls the Add method on the Web service and displays the return value.

Watching SOAP Traffic

As you start playing with Web services, at some point you will want to look at the SOAP packets being exchanged between your client and a Web service. Here are two excellent tools.

PCapTrace is a free packet capture tool that can be downloaded from www.pocketsoap.com/pcaptrace/. Simply run this tool and specify the server and port your code is connecting to. The tool captures and displays all the data. You can also log the data.

ProxyTrace is yet another free tool that acts as an HTTP proxy server. It can be downloaded from www.pocketsoap.com/tcptrace/pt.asp. The only drawback with this tool is that you need to modify your client code to go through a proxy server.


At this point, it is worth mentioning that Visual Studio .NET makes it easy to generate a Web service client. In the Solution Explorer, right-click your project and select Add Web Reference. Enter the URL for the Web service in the ensuing dialog box. The wizard discovers and displays the Web service(s). Clicking the Web service generates a proxy class for the Web service and adds it to your project. By default, the namespace of the generated proxy class is the host name of the URL. For example, selecting our Calculator Web service from localhost generates a proxy class localhost.MyCalculator. However, you can change the localhost namespace to something more meaningful by selecting the localhost folder in the Solution Explorer and renaming it.

Managing State in ASP.NET Web Services

Inheriting a Web service class from WebService makes it easy to access the state management options of ASP.NET. The WebService class contains many of the common ASP.NET objects, including the Application and Session objects.

The Application object provides a mechanism for storing data that is accessible to all code running within the Web application. The following code excerpt demonstrates a simple example of how the Application object can be used to track the usage of the Web application.

// Project Calculator. File Calculator.asmx

[WebMethod(Description=
     "Number of times this application has been used")]
public int ApplicationUsage() {
     String USAGE = "Usage";
     if (Application[USAGE] == null) {
       // First time
       Application[USAGE] = 0;
     }
     // Increment the usage count.
     Application[USAGE] = ((int) Application[USAGE]) + 1;
     return  (int) Application[USAGE];
}

The Application object stores each bit of state information as a name–value pair. In the preceding code, a counter is being stored under the name USAGE. Each time the method is called, the counter is incremented by one.

Whereas the Application object is used to store data at the application level, irrespective of the number of clients connected to the application, the Session object allows data to be stored on a per-client session basis. The following code excerpt shows how to create a hit counter for per-user session:

// Project Calculator. File Calculator.asmx

[WebMethod(EnableSession=true)]
public int PerUserSessionUsage() {
     String USAGE = "Usage";
     if (Session[USAGE] == null) {
       // First time
       Session[USAGE] = 0;
     }

     // Increment the usage count.
     Session[USAGE] = ((int) Session[USAGE]) + 1;
     return  (int) Session[USAGE];
}

As can be seen, using the Session object is similar to using the Application object. The important thing to note is that to use the Session object, the session state must be enabled on the Web service method. This is done by setting the EnableSession property of the WebMethod attribute to true.

ASP.NET keeps track of the session by means of a client-side cookie. The client code should be enabled to store the cookie. This is done by setting the CookieContainer property to a new System.Net.CookieContainer object, as highlighted in the following code:

// Project Calculator/MyClient

calc.CookieContainer = new System.Net.CookieContainer();
int count = calc.PerUserSessionUsage();
count = calc.PerUserSessionUsage();
count = calc.PerUserSessionUsage();

Customizing the Web Service Interface

Sometimes it may be necessary to control the auto-generated WSDL document and the contents of the SOAP messages. In this section, we explore some important possibilities.

Protocols

By default, ASP.NET supports three different HTTP protocols for communication: HTTP-GET, HTTP-POST, and HTTP-SOAP. A client application can use any of these three protocols to communicate. When you're ready to go to production, however, you'll probably want to stick to just SOAP. Most Web service implementations today rely on HTTP-SOAP because it offers a much more robust and extensible protocol. For example, SOAP defines standards for encoding data and communicating error information.

To exclude HTTP-GET and HTTP-POST from your Web service's WSDL, you need to add the configurationsystem.webwebServicesprotocol XML path in your application's web.config file. You need to add a <remove> element for each protocol that you want to remove, as shown here:

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

Configuring your Web service this way has the following effects:

  1. The removed protocols are excluded from the service's WSDL document.

  2. The clients receive an error if they attempt to use these protocols to invoke the Web service.

  3. Disabling HTTP-GET disables the autogenerated test page. Although not a big deal during development, removing the protocols you don't use is an important step before a Web service goes into production.

SOAP Message Formatting

WSDL defines two styles for how a Web service method can be formatted in a SOAP message: document and RPC. Document formatting is designed for XML document-based messaging. It doesn't have, for example, the notion of method parameter ordering. RPC formatting states that all parameters are encapsulated within a single XML element named after the XML Web service method and that each XML element within that XML element represents a parameter named after the parameter it is representing. More information about RPC formatting can be found in Section 7 of the SOAP specifications (www.w3.org/TR/SOAP/#_Toc478383532).

By default, ASP.NET Web services use document formatting. However, it is possible to specify RPC formatting on a Web service method. This is done using the attribute SoapRpcMethodAttribute (namespace System.Web.Services.Protocols), as illustrated in the following code excerpt:

// Project Calculator/Calculator.asmx

[SoapRpcMethod]
[WebMethod]
public int Multiply(int a, int b, out int c) {
     c = a * b;
     return c;
}

There are many properties that can be set on SoapRpcMethodAttribute. For example, the OneWay property can be set to true, in which case the client call does not have to wait for the Web server to finish processing the message. Check the SDK documentation for OneWay as well as all other properties available on the attribute.

Tracing ASP.NET Web Services

A discussion on ASP.NET Web services will not be complete without talking about how to trace the Web services.

ASP.NET provides a class TraceContext that makes it easy to add trace statements to your applications, and to capture and view them while the application is executing. The class implements two methods, Write and Warn, that you can use for adding traces to your application.

The TraceContext object is available as a property Trace on the current HTTP context. That is, the object can be accessed as HttpContext.Current.Trace anywhere from the ASP.NET application or as Context.Trace in case of WebService methods, as illustrated in the following code excerpt:

// Project Calculator. File Calculator.asmx

[WebService(Namespace="http://localhost/WSRemoting/")]
public class MyCalculator : WebService {

     // Simple Web Service Demo
     [WebMethod]
     public int Add(int a, int b) {
       Context.Trace.Write("Add called");
       return (a+b);
     }
}

Just adding the trace statements to your code is not enough; tracing has to be enabled in order to be able to view the traces. You can enable application-level tracing by adding a <trace> element to your Web.config file, as illustrated below:

<configuration>
  <system.web>
    <trace enabled="true" requestLimit="40" />
 </system.web>
</configuration>

When application-level tracing is enabled, ASP.NET writes the output details to an application-wide trace viewer application called Trace.axd. Trace.axd is an HTTP handler that you can use to watch a bunch of requests. The number of requests to be saved can be configured with an optional requestLimit attribute in your Web.config file. The default value (and the minimum) is ten. Once the number of requests reaches requestLimit, tracing is automatically disabled.

To view the traces, issue the URL http://<Machine>/<AppRoot>/Trace.axd from Internet Explorer, where <Machine> is the machine on which your ASP.NET application is running and <AppRoot> is the name of the IIS virtual directory of your application. And don't worry that the trace viewer (Trace.axd) does not physically exist as a file in the root directory of your application.

The trace viewer lets you view your executed trace statements. It also lets you get detailed information on a specific trace.

Note that the trace viewer does not update the view automatically. You will need to hit the refresh button (F5) from your browser to get an up-to-date view.

This concludes our discussion on developing and using ASP.NET Web services. In Chapter 8, we will look at how to invoke Web services asynchronously. In Chapter 9, we will look at how to secure your ASP.NET Web services. In Chapter 10, we will see how Web services can participate in a transaction. If you wish to experiment with Web services, I suggest that you use the Web Services Wizard that comes with Visual Studio .NET. Besides generating the Web services template, it also creates the necessary configuration (web.config) and discovery (.disco) files. For a good article on getting started with Web services using Visual Studio .NET, check out [MS-02].

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.112.82