Building client/server applications generally seems to resemble the chicken and egg problem. You need a server to test the client and a client to test the server. An echo server will bounce back any information it receives to the client who sent the data. Echo servers allow for a client application to test its connection and ensure that the data being sent is correct. Implementing an EchoService using .NET WebServices will serve as a good starting point.
VS.NET supports creation of WebServices directly from the IDE. VS.NET will connect to the specified IIS server using FrontPage extensions to open a Web folder, just as with the WebApplication developed in the previous chapters. Figure 4.4.1 shows the new project dialog for creating a WebService.
WebServices, as created by VS.NET, consists of two files—an asmx file and a C# source file. However, only the asmx file is necessary because all the C# code can reside within the asmx file. However, this is not the approach that will be taken when developing the examples presented in this chapter. Listing 4.4.1 shows the C# code for the EchoService WebService. In addition, I've changed the name of the default class from Service1 to EchoServer for clarity.
The EchoService.asmx.cs in Listing 4.4.1 lays out a basic WebService. The EchoServer class inherits from System.Web.Services.WebService base class. The WebService base class does not require the derived class to override or implement any methods; instead, the WebService base class merely provides the implementation necessary to support the method invocations.
The EchoServer class itself provides only a single method that is exposed to clients—Echo. Notice the attribute used on the method. This [WebMethod] attribute is used by the runtime to locate methods that the class exposes to clients. In the same way that the DBAccess class implemented for the EmployeeBrowser example, the runtime makes use of the Reflection API to locate a WebMethod and invoke it with the proper parameters.
For IIS to host the WebService, there needs to exist an asmx file in the virtual Web directory containing the EchoService WebService. This asmx file is used to wire-up the WebService code to the .dll and class providing the actual WebService. This basic wiring of the asmx file to the necessary C# code is shown in Listing 4.4.2.
1: <%@ WebService Language="c#" 2: Codebehind="EchoService.asmx.cs" 3: Class="EchoService.EchoService" %> 4: |
As you can see, there really isn't too much to the asmx file. As with aspx pages, there is a language directive, a Codebehind directive, that specifies the source file and a class directive that gives the qualified name of the class providing the WebService implementation.
Because the EchoService has been implemented as a C# source file and not inline script, the EchoService.asmx.cs file needs to be compiled and the resulting .dll copied to the bin directory of the current virtual directory hosting the EchoService. VS.NET will automatically perform this process during the build process. Testing the service merely requires accessing the asmx file with the Internet Explorer Web browser, as show in Figure 4.4.2.
The WebServices system creates a basic HTML form from which the WebService can be tested. Locate the input box, enter some text, and click the Invoke button. This will cause the Echo method to be invoked and the return XML will be displayed in the browser (see Figure 4.4.3).
To invoke the WebService from C# code, a proxy class needs to exist. A proxy represents a gateway to the actual server code. In turn, the server has a stub to which the proxy connects. Figure 4.4.4 is a simple illustration of this.
To create a proxy, you need to determine the particular protocol you want to use. The choices are HTTP POST, HTTP GET, or SOAP. Based on that decision, the proxy can then be derived from the property base class from System.Web.Services.Protocols.X, where X represents the corresponding protocol.
Listings 4.4.3 through 4.4.5 show the implementation for SOAP, HTTP POST, and HTTP GET, respectively. The basic structure for each implementation is the same. The differences to note include the base classes and the attributes applied to the Echo method and the parameter. Using the proxy object is no different than using any other object. Instantiate an instance and invoke the method with the proper parameter specified.
The good news is that you don't have to type this code by hand. Shipped along with the .NET SDK is a tool named WSDL.exe whose purpose is to generate client code for WebServices. Running WSDL.exe with no parameters will display the command lines and their meanings. The basic form for WSDL looks like the following:
WSDL <url or wsdl document> <language> <protocol>
WebServices can be invoked synchronously or asynchronously. The common case is to use the synchronous method invocation. Asynchronous method invocation is useful in cases where the method call requires an extended time period for processing, the idea being that the client can continue to work while waiting for the async-response to return. This allows for other work to be performed without tying up the client application.
The various bindings—SOAP, HTTP GET, and HTTP POST—present an opportunity to develop a client application that utilizes a factory to create and return the requested binding. A WebService is capable of exposing several objects, and each of those objects can be viewed in terms of a public interface. This being the case, an interface that defines the public methods of a WebService can then be defined, and then each proxy implements this interface.
With respect to the EchoService, the interface for the WebService itself can be expressed as follows:
public interface IEchoService { string Echo( string Message ); }
This interface is conceptual only; in actual fact, the EchoService does not have an interface that can be referenced.
The Factory pattern helps to isolate clients from the underlying type that a factory creates. The Factory returns a well-known type—in this case, the IEchoService interface. Each proxy, as shown in Listings 4.4.3, 4.4.4 and 4.4.5, needs to implement the IEchoService interface. Actually, the listed proxies already do and only need the IEchoService interface added to the class declaration.
The ProxyFactory class will take an enum as a parameter to determine the underlying object to create and return. Listing 4.4.6 shows the ProxyFactory implementation.
The ProxyFactory class encapsulates the creation of the requested proxy based on the binding passed into to the ConstructProxy method. Because the IEchoService interface has been implemented by each of the underlying proxy implementations, the ProxyFactory needs only to construct the proper proxy class and return the IEchoService interface.
To put the WebService to the test, the following WinForms client provides a UI interface to the EchoService. Using VS.NET, create a C# Windows Forms application and construct the form shown in Figure 4.4.5.
Because the forms designer generates most of the code, only the relevant sections need to be reviewed rather than the complete code listing. Add the following protected variable:
private ProxyProtocol SelectedProtocol=ProxyProtocol.SOAP;
This will allow the application to track the requested protocol for the WebService method invocation. Be sure to include the using ProxyFactory in the namespace declarations.
Next, I've hooked up each radio button to the same Click handler, which contains the following code:
protected void OnOpt_Click( object sender, EventArgs e ) { if( sender == optSOAP) this.SelectedProtocol = ProxyProtocol.SOAP; else if( sender == optHttpPost ) this.SelectedProtocol = ProxyProtocol.HttpPost; else this.SelectedProtocol = ProxyProtocol.HttpGet; }
This code serves to update the SelectedProtocol variable based on the currently selected radio button. Refer to the WinForms chapters for assigning delete handlers for controls.
Lastly, the invocation of the WebService happens when the Invoke button raises a Click event.
protected void btnInvoke_Click (object sender, System.EventArgs e) { //Get an IEchoService interface IEchoService echo = ProxyFactory.ConstructProxy( this.SelectedProtocol ); this.lblResponse.Text = echo.Echo( this.txtMessage.Text ); this.txtMessage.Text = ""; }
With the event handler code in place, the Windows Forms client is ready to go. Figure 4.4.6 shows the client application ready to invoke the Echo WebService. In Figure 4.4.7, the result of the WebService invocation is displayed in the appropriate label showing the text echoed back from the EchoService.
Now that the common case of using the synchronous method invocation has been discussed, the next step is to understand the asynchronous method invocation.
Asynchronous WebService invocation requires a delegate with the following method signature:
<access modifier> void <name>( System.IAsyncResult )
Fortunately, or unfortunately, there is no dark secret to how this mechanism works. The basic process for the call is the same as the synchronous version, only now a thread is created to handle the process of sending and receiving the request. After the request has been completed, an event is fired and the attached delegate is called.
Look at the various generated WebService proxies in Listings 4.4.3, 4.4.4 and 4.4.5; each proxy defines the following method:
public System.IAsyncResult BeginEcho(string message, System.AsyncCallback callback, object asyncState)
Just as the Echo method takes a string parameter, so does the BeginEcho method. In addition, the BeginEcho method requires a delegate for the callback and an object to which the asynchronous request belongs. Rather than list an entire application to invoke this method, the source code snippet in Listing 4.4.7 demonstrates the use of the asynchronous method invocation.
1: //Create the proxy and invoke the BeginEcho method 2: EchoServiceSoapProxy sp = new EchoServiceSoapProxy( ); 3: sp.BeginEcho("Hello", new System.AsyncCallback(this.CallBack), sp ); 4: 5: //The callback for the asynchronous result 6: protected void CallBack( System.IAsyncResult ar ) { 7: EchoServiceSoapProxy sp = (EchoServiceSoapProxy)ar.AsyncState; 8: this.button1.Text = sp.EndEcho( ar ); 9: } |
After the CallBack method is invoked, the original EchoServiceSoapProxy object is obtained from the IAsyncResult interface. Next, the EndEcho method is called to obtain the results of the asynchronous WebService method call.
Hopefully the EchoService is a good introduction to the ease of WebService development and client consumption of such WebServices.
3.14.251.57