Custom Clients


Back in Figure 5-1, you saw that the proxy class you can generate from a Web service’s WSDL file also abstracts over a pair of message processing and serialization routines. Like those on the server side, they might become undesirable, too, so you need to know how to write our own proxy classes for the client.

The process is a great deal like working on the server side except you’re working with the System.Net namespace rather than System.Web. As Figure 5-8 shows, it’s just a case of knowing which objects to work with.

click to expand
Figure 5-8: You can implement the client-side interaction with Web services using System.Net.

  • You read and write the SOAP requests and responses by using the streaming and DOM APIs in the same way you do on the server. Of course, we’re now writing the request and reading the response.

  • An HTTP request is modeled by System.Net.HttpWebRequest. The standard HTTP headers are given as class properties, and any nonstandard ones, such as SOAPAction, can be appended to its Headers collection. You can retrieve the stream that will contain the HTTP request body by using the HttpWebRequest object’s GetRequestStream method.

  • Once the request has been prepared, you send it using the HttpWebRequest.GetResponse method. This returns a HttpWebResponse object that represents the corresponding response from the server.

  • You can retrieve the stream containing the SOAP response in the body of the HTTP message by using the HttpWebResponse.GetResponseStream method.

Let’s take an example and see this in action. We’ll build a client for SchemaHandler1.ashx, which we built earlier. If you’ll recall, the handler expects a SOAP request containing the name of an album and the artist that recorded it and returns a message string saying whether the operation was successful on the server. From a user-interface point of view, the client is very simple (as shown in Figure 5-9). We need a couple of text boxes where the user can enter the album (txtAlbum) and artist (txtArtist) details, a submit button (btnGo) to send the SOAP request, and some means of displaying the results. In this case, we’ve chosen a simple label control (lblResponse) to display them verbatim.

click to expand
Figure 5-9: The user-interface elements of the client don’t need to be very complex.

The submit button’s Click event handler sets everything in motion and neatly abstracts the steps needed on the client into three simple operations:

private void btnGo_Click(object sender, System.EventArgs e) {

First we create an HttpWebRequest object for our message with the static method Create inherited from its parent class. WebRequest is an abstract class built without any specific transport protocol in mind, so we need to cast it to an instance of its subclass:

    //Create web request object     HttpWebRequest soapRequest = (HttpWebRequest)WebRequest.Create(         "http://localhost/wscr/"         + "05/schemahandler/SchemaHandler1.ashx");

Then it’s a case of building the request and retrieving the response for display:

    HttpWebResponse soapResponse = BuildAndSendSOAPRequest(soapRequest);     lblResponse.Text = ReadDocument(soapResponse.GetResponseStream()); }

Building an HTTP request containing a SOAP message requires the same actions as building a SOAP message but with the addition of setting the HTTP headers as required. The BuildAndSendSOAPRequest method in our example client demonstrates this well:

private HttpWebResponse BuildAndSendSOAPRequest(HttpWebRequest webreq) {

As mentioned earlier, the standard headers are exposed as read-write properties of the HttpWebRequest object and any custom headers must be added to the Headers collection. Here, of course, we need to add a SOAPAction header. It’s worth noting that the HttpWebRequest object supports the use of cookies for a state management system via its CookieContainer property.

    //Add HTTP headers to request     webreq.Method = "POST";     webreq.ContentType = "text/xml";     webreq.Headers.Add("SOAPAction", "AddRecord");

With the headers set as required, it’s just a matter of flowing the contents of the HTTP message body into the stream exposed by GetRequestStream. In this case, that’s the SOAP request we want to send, and we’ll do that with an XmlTextWriter object:

    //Create XmlTextWriter to build SOAP request     XmlTextWriter soapWriter =          new XmlTextWriter(webreq.GetRequestStream(), Encoding.ASCII);     //Write Xml Declaration     soapWriter.WriteStartDocument();     //Write SOAP Envelope and Body Elements     soapWriter.WriteStartElement("env", "Envelope",          "http://schemas.xmlsoap.org/soap/envelope/");     soapWriter.WriteStartElement("Body",          "http://schemas.xmlsoap.org/soap/envelope/");     //Write AddRecord Element     soapWriter.WriteStartElement("a", "AddRecord",          "http://www.notashop.com/wscr");     //Write Album and artist elements     soapWriter.WriteElementString("album",          "http://www.notashop.com/wscr", txtAlbum.Text);     soapWriter.WriteElementString("artist",          "http://www.notashop.com/wscr", txtArtist.Text);     //End Element     soapWriter.WriteEndElement();     soapWriter.WriteEndElement();     soapWriter.WriteEndElement();                //End XML Document     soapWriter.WriteEndDocument();

Once your message is complete, you post it to the target URI with a call to GetResponse. This returns a WebResponse object, which, as before, you can cast into an HttpWebResponse object to gain a little more control. Note that you must Close the Writer object before you call GetResponse or it will return an exception.

    //Write to file and close     soapWriter.Close();     return (HttpWebResponse)webreq.GetResponse(); }

If the server fails to respond or returns a status code other than 200 OK, GetResponse throws a WebException, which you can handle in a try/catch block. WebException objects have two properties beyond those of a generic Exception object that are useful to us:

  • Response, which contains the actual error message from the server

  • Status, which contains the HTTP response code that the server sent back

Assuming that all has gone well, our client now has a reply from the server encapsulated in an HttpWebRequest object, the body of which is available as a Stream from its GetResponseStream method. In our simple client, we call a method that pulls out the entire SOAP message from the stream and sends it to the waiting label control:

lblResponse.Text = ReadDocument(soapResponse.GetResponseStream());   private string ReadDocument(Stream ResponseStream) {     XmlTextReader responseReader = new XmlTextReader(ResponseStream);     responseReader.MoveToContent();     string XmlString = responseReader.ReadOuterXml();     responseReader.Close();     return XmlString; }

The SOAP tags are ignored by the browser, but the text message—whether success or error—is not, so we have our feedback from the service. It’s a quick hack but demonstrates the idea nicely. In real-world situations, you can parse the results of the response back out into your application using either of the XML APIs we’ve discussed, or you might use XSL to transform it into something more pleasing to the eye.




Programming Microsoft. NET XML Web Services
Programming MicrosoftВ® .NET XML Web Services (Pro-Developer)
ISBN: 0735619123
EAN: 2147483647
Year: 2005
Pages: 172

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