If you only want to request a file from a particular URI, then you will find that the easiest .NET class to use is System. Net. WebClient. This is an extremely high-level class designed to perform basic operations with only one or two commands. The .NET Framework currently supports URIs beginning with the http: https: and file: identifiers.
It is worth noting that the term URL (Uniform Resource Locator) is no longer in use in new technical specifications, and URI (Uniform Resource Identifier) is now preferred. URI has roughly the same meaning as URL, but is a bit more general because URI does not imply you are using one of the familiar protocols, such as HTTP or FTP.
Two methods are available for downloading a file using Web Client. The method you choose depends on how you want to process the file’s contents. If you simply want to save the file to disk, then you use the DownloadFile() method. This method takes two parameters: the URI of the file and a location (path and file name) to save the requested data:
More commonly, your application will want to process the data retrieved from the Web site. To do this, you use the OpenRead() method, which returns a Stream reference that you can then use to retrieve the data into memory:
Basic Web Client Example
The first example demonstrates the WebClient. OpenRead() method. You will display the contents of the downloaded page in a ListBox control. To begin, create a new project as a standard ell Windows Forms application and add a ListBox called listBox with the docking property set to DockStyle. Fill. At the beginning of the file, you will need to add the System.Net and System. IO namespaces references to your list of using directives. You then make the following changes to the constructor of the main form:
In this example, you connect a StreamReader class from the System. 10 namespace to the network stream. This allows you to obtain data from the stream as text through the use of higher-level methods, such as ReadLine(). This is an excellent example of the point made in Chapter 25, Manipulating Files and the Registry, about the benefits of abstracting data movement into the concept of a stream.
Figure 41-1 shows the results of running this sample code.
The WebClient class also has an OpenWrite() method. This method returns a writable stream for you to send data to a UR!. You can also specify the method used to send the data to the host; the default method is POST. The following code snippet assumes a writable directory named accept on the local machine. The code will create a file in the directory with the name newfile.txt and the contents Hello World:
StreamWriter streamWriter = new StreamWriter(stream);
The WebClient class also features UploadFile() and UploadData() methods. You use these methods when you need to post an HTML form or to upload an entire file. UploadFile() uploads a file to a specified location given the local file name, whereas UploadData() uploads binary data supplied as an array of bytes to the specified URI (there is also a DownloadData() method for retrieving an array of bytes from a URI):
WebRequest and WebResponse Classes
Although the webClient class is very simple to use, it has very limited features. In particular, you cannot use it to supply authentication credentials – a particular problem with uploading data is that not many sites will accept uploaded files without authentication! It is possible to add header information to requests and to examine any headers in the response, but only in a very generic sense – there is no specific support for anyone protocol. This is because WebClient is a very general-purpose class designed to work with any protocol for sending a request and receiving a response (such as HTTP or FTP). It cannot handle any features specific to anyone protocol, such as cookies, which are specific to HTIP. To take advantage of these features, you need to use a family of classes based on two other classes in the System, yet namespace: WebRequest and WebResponse.
You start off by seeing how to download a Web page using these classes. This is the same example as before, but using WebRequest and WebResponse. In the process, you will uncover the class hierarchy involved, and then see how to take advantage of extra HTTP features supported by this hierarchy.
The following code shows the modifications you need to make to the BasicWebClient sample to use the WebRequest and WebResponse classes:
In the code example, you start by instantiating an object representing a Web request. You don’t do this using a constructor, but instead call the static method WebRequest .·Create(). As you will learn in more detail later in this chapter, the WebRequest. class is part of a hierarchy of classes supporting different.
network protocols. In order to receive a reference to the correct object for the request type, a factory mechanism is in place. The WebRequest .Create() method will create the appropriate object for the given protocol.
The WebRequest class represents the request for information to send to a particular URI. The URI is passed as a parameter to the Create() method. A WebResponse represents the data you retrieve from. the server. By calling the WebRequest .GetResponse () method, you actually send the request to the Web server and create a WebResponse object to examine the return data. As with the WebClient object, you can obtain a stream to represent the data, but in this case you use the WebResponse .GetResponseStream() method.
Other WebRequest and WebResponse Features
This section briefly discusses a few of the other areas supported by WebRequest, WebResponse, and other related classes.
HTTP Header InformatIon
An important part of the HTTP protocol is the ability to send extensive header information with both request and response streams. This information can include cookies and the details of the particular browser sending the request (the user agent). As you would expect, the .NET Framework provides full support for accessing the most significant data. The WebRequest and WebResponse classes provide some support for reading the header information. However, two derived classes provide additional HTTP-specific information: Http WebRequest and Http WebResponse.As you will see in more detail later, creating a WebRequest with an HTTP URI results in an Ht tpWebReques t object instance. Because
HttpWebRequest is derived from WebRequest, you can use the new instance whenever a WebRequest is required. In addition, you can cast the instance to an Http WebRequest reference and access properties specific to the HTTP protocol. Likewise, the GetResponse() method call will actually return an Http WebResponse instance as a WebResponse reference when dealing with HTTP.Again, you can perform:.a simple cast to access the HTTP-specific features.
You can examine a few of the header properties by adding the following code before the GetResponse() method call:
The Timeout property is specified in milliseconds, and the default value is 100,000. You can set the Timeout property to control how long the WebRequest object will wait for the response before throwing a WebException. Youcan check the WebException. Status property to view the reason for an exception. This enumeration includes status codes for timeouts, connection failures, protocol errors, and more.
The KeepAlive property is a specific extension to the HTTP protocol,.so you access this property through an Http WebRequest reference. KeepAlive allows multiple requests to use the same connection, saving time in closing and reopening connections on subsequent requests. The default value for this property is true. The AllowAutoRedirect property is also specific to the Http WebRequest class. Use this property to control whether the Web request should automatically follow redirection responses from the Web server. Again, the default value is true. If you want to allow only a limited number of redirections, then set the MaximurnAutomaticRedirections property of the Http WebRequest to the desired number.
Although the request and response classes expose most of the important headers as properties, you can also use the Headers property itself to view the entire collection of headers. Add the following code after the GetResponse() method call to place all of the headers in the ListBox control:
This example code produces the list of headers shown in Figure 41-2.
Another property in the WebRequest class is the Credentials property. If you need authentication credenticirs to accompany your request, then you can create an instance of the NetworkCredential class (also from the System.Net namespace) with a usename and password. You can place the following code before the call to GetResponse().
NetworkCredential myCred = new etworkCredent1al(‘myusername’, ‘mypassword’);
wrq.Credentials = rnyCred;
Working with Proxies
You will find in enterprises that many firms must deal with a proxy server to make any type of HTTP or FTP request. Many times, the proxy server, which routes all of the organization’s requests and responses, uses some form of security (usually a usemame and a password). For your applications that use the webClient or the WebRequest objects, you might need to take these proxy servers into account. As with the preceding NetworkCredential object, you are going to want to use the WebProxy object before you
make it call to make the actual request.
webProxy wp = new WebProxy(‘192.168.1.100′, true);
wp.Credentials = new NetworkCredential(“userl’, ‘userlPassword”);
webResponse wrs = wrq.GetResponse();
If you also require a designation of the user’s domain in addition to its credentials, then you would use a different signature on the NetworkCredential instantiation:
Asynchronous Page Requests
An additional feature of the WebRequest class is the ability to request pages asynchronously. This feature is significant because there can be quite a long delay between sending a request to a host and receiving the response. Methods such as WebClient. DownloadData() and WebRequest . GetResponse() will not return until the response from the server is complete. You might not want
your application frozen due to a long period of inactivity, and in such scenarios it is better to use the BeginGetResponse () and EndGetResponse() methods. BeginGetResponse() works asynchronously and returns almost immediately. Under the covers, the runtime will asynchronously manage a background thread to retrieve the response from the server. Instead of returning a WebResponse object, BeginGetResponse() returns an object implementing the IAsyncResult interface. With this interface, you can poll or wait for the response to become available and then invoke EndGetResponse() to gather the results.
You can also pass a callback delegate into the BeginGetResponse() method. The target of a callback delegate is a method returning void and accepting an IAsyncResult reference as a parameter. When the worker thread is finished gathering the response, the runtime invokes the callback delegate to inform you of the completed work. As shown in the following code, calling EndGetResponse() in the callback method allows you to retrieve the WebResponse object:
Notice that you can retrieve the original webRequest object by passing the object as the second parameter to BeginGetResponse() The third parameter is an object reference known as the state parameter. During the callback method, you can retrieve the same state object using the IAsyncState property of IAsyncResult.