The Web's Transport: HTTP



The Web's Transport: HTTP

On top of TCP/IP, the most popular transport in the world—HTTP—is built. HTTP is a connection-oriented protocol that is based on request and response messages. Whereas TCP and UDP are based on binary layouts of data for destination and other metadata on the request, HTTP is based on text.

Here is a request message:

GET /CRWeb/CRService.html HTTP/1.1 

And here is a response message:

HTTP/1.1 200 OK 
Content-Type: text/xml; charset=utf-8
Content-Length: nnn

<HTML>
     <BODY>
          This is an HTML page.
     </BODY>
</HTML>

At the beginning of any HTTP request is the verb and location of the resource to which the verb applies. By far, the most popular verb is GET, which will return the data at the location specified.

There are several ways to make HTTP requests with the .NET Framework, and this chapter covers the two most powerful ways. The first is a little more simplistic: the WebClient class. The other classes are in the WebRequest API, which is harder to use, but much more powerful.

The WebClient Class

To use the WebClient class, you first need to construct the object:

WebClient client = new WebClient(); 

Next, you need to set the credentials for the request message, assuming that you want to set HTTP authentication. If the Web resource is anonymous, you can skip this step. Otherwise, to set the credentials, you can explicitly set a user and the user's password, or set the credentials to be the current user. Following is an example line that sets the credentials property to be the default credentials:

client.Credentials = CredentialCache.DefaultCredentials; 

Now you can make a GET request—the usual kind of request that a browser makes when no data is being sent to a Web server—with either the DownloadData or DownloadFile method.

Byte[] page = client.DownloadData(txtUrl.Text); 

Next you can convert the byte array to a string, or whatever other parsing you want:

txtResults.Text = System.Text.Encoding.ASCII.GetString(page); 

You can use WebClient to upload data, with the POST verb, through the UploadFile and UploadData methods. However, these methods, like the other WebClient methods, have a major problem: They are all synchronous methods that will block until the method is done.

The WebRequest Classes

The other major HTTP API comprises the WebRequest classes. WebRequest is an abstract class, and it is implemented with HttpWebRequest. This more complicated class includes asynchronous support. It is a stream-based API as well.

In this example application, we will send a SOAP message to a server. The Windows form application will enable the user to set the URL, set the SOAPAction, and input the SOAP message. This application, which is very useful for debugging failures and testing Web service endpoints, will end up resembling Figure.

3. An Example WebRequest Application

graphics/07fig03.gif

To create a WebRequest object, you must use the static Create method of the WebRequest class:

WebRequest request = WebRequest.Create( txtURL.Text ); 

To set the credentials, you do almost the same thing you would for the WebClient:

request.Credentials = CredentialCache.DefaultCredentials; 

Next, the application should set the verb to POST, and the SOAPAction to the action the form specifies:

request.Method = "POST"; 
request.ContentType = "text/xml";
request.Headers.Add( "SOAPAction", txtAction.Text );

Now, the application needs to take the input for the request SOAP message, and write it out to the response Stream of the WebRequest:

Byte[] requestBuffer = 
             System.Text.UTF8Encoding.UTF8.GetBytes( txtRequest.Text );
request.ContentLength = requestBuffer.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write( requestBuffer, 0, requestBuffer.Length);
requestStream.Close();

The WebRequest class provides a method for accessing the Stream used to send POST data. This stream can take any kind of data; it is a basic Stream from the System.IO namespace.

Setting ContentLength

Notice that we are setting the ContentLength manually. The WebRequest object won't do this for you. If you don't set this property properly, you won't receive a response from the server. Instead, at some point you will merely get a timeout exception.

The WebRequest class as found in the System.Net class is abstract; that is, it doesn't contain any implementation. Instead, it provides a transport-independent model for implement request–response protocols, such as HTTP. In fact, the actual implementation being used here is the HttpWebRequest class. This class pattern also specifies the need to implement a class for the WebResponse. In this example, we used the HttpWebResponse class.

Notice that we didn't create a WebRequest class itself, but instead called the static method Create(String Url). This method looks up registered classes that implement WebRequest, and returns the most appropriate one, usually based on the URL prefix, such as HTTP: or HTTPS:.

You may have noticed that we never cast these classes to their actual types in this example. In fact, you rarely will need to do this, because the WebRequest class is itself designed to handle many of the most common scenarios you will encounter. The most common reason to cast down to HttpWebRequest would be to set an HTTP-specific header. For example, if you wanted to set the User-Agent string, you could use the UserAgent property:

WebRequest request = WebRequest.Create( txtURL.Text ); 
Request.UserAgent = "OurNewUserAgent";