|
Application Protocols
The application protocols level contains classes designed for resolving specific protocols. Resources that can be resolved using these protocols are most often represented by a URI. In version 1.1 of the .NET Framework, the supported schemes include HTTP, HTTPS, and FILE. In newer release of the .NET Framework, this layer will be enhanced to include FTP protocol support as well. Each of these protocols implements the general request-response pattern that will be described in the next section. Figure 6-4 provides a graphical representation of the key application protocol classes in version 1.1 of System.Net.
Figure 6-4: Application protocol classes in version 1.1 of System.Net
Protocol Support
The HTTP protocol is supported primarily by the HttpWebRequest and HttpWebResponse classes in System.Net. These classes provide a complete implementation of the HTTP 1.1 and 1 protocols. The feature set includes support for all of the HTTP verbs defined in RFC 2616 as well as custom commands, HTTP pipelining, and chunked uploading and downloading of content. HttpWebRequest and HttpWebResponse have been designed to work well under situations that require high load and scale. They’re also suitable for use both in client application scenarios and n-tier server scenarios. The HTTP support in System.Net is described in more detail in Chapter 10. The following example demonstrates how to download a file using the HTTP classes. |
static void Main()
{
try
{
// Create the request object
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/file.htm");
// Optionally, you can set HTTP-specific elements on
// the request, such as the User-Agent header
request.UserAgent = "Test Client version 1.0";
// Issue the request
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// Read the content
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII);
string content = reader.ReadToEnd();
// Display the content to the console
Console.WriteLine(content);
// Close the response
response.Close();
}
catch(WebException wex)
{
Console.WriteLine(wex.ToString());
// Check the status to see if there might be a response object
if(wex.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)wex.Response;
Console.WriteLine();
Console.WriteLine("The protocol error returned was '" + response.StatusCode.ToString() + "'.");
response.Close();
}
}
}
Sub Main()
Try
' Create the request object
Dim request As HttpWebRequest = WebRequest.Create("http://www.contoso.com/file.htm")
' Optionally, you can set HTTP-specific elements on
' the request, such as the User-Agent header
request.UserAgent = "Test Client version 1.0"
' Issue the request
Dim response As HttpWebResponse = request.GetResponse()
' Read the content
Dim reader As New StreamReader(response.GetResponseStream(), Encoding.ASCII)
Dim content As String = reader.ReadToEnd()
' Display the content to the console
Console.WriteLine(content)
' Close the response
response.Close()
Catch wex As WebException
Console.WriteLine(wex.ToString())
' Check the status to see if there might be a response object
If wex.Status = WebExceptionStatus.ProtocolError Then
Dim response As HttpWebResponse = wex.Response
Console.WriteLine()
Console.WriteLine("The protocol error returned was '" & response.StatusCode.ToString & "'.")
response.Close()
End If
End Try
End Sub
The HTTP protocol layer includes the ServicePoint and ServicePointManager classes for controlling connection semantics associated with the HTTP requests between an application and a remote host. The ServicePointManager class is used to specify settings that apply to all connections made by the application, whereas the ServicePoint class provides the ability to change settings on a host- by-host basis. For example, the default connection limit is two connections per application and host pair; however, this limit can be changed on a per-host basis through the ServicePoint class or globally for all host connections in the application through the ServicePointManager class. Connection semantics can be specified through the ServicePoint.ConnectionLimit property or the ServicePointManager.DefaultConnectionLimit property. Other interesting features that can be manipulated using the connection management classes include pipelining, certificate authentication, SSL encryption, setting the behavior of the Expect HTTP header (by default this behavior is 100-continue), and use of the TCP Nagle algorithm.
Error handling for HTTP is accomplished using the WebException class. WebException contains a Status property to indicate the reason the WebException was thrown. This value is useful because it helps to determine whether a valid HttpWebResponse object that can be used to read the response from the server is associated with the WebException even though an exception was thrown. For example, an authentication challenge that’s not handled successfully by the client will result in a WebException. However, it’s possible that the server included additional information in the response, so reading the data sent back from the server is still interesting in this case. There are other cases where the WebException occurs before the connection to the remote host has been established, such as a name resolution failure. In these cases, no HttpWebResponse object is associated with the WebException. Because of this model, it’s important to always check the Status property before accessing the Response property on WebException.
Note: The WebException.Status property should not be confused with the protocol status codes that can be returned by an HTTP server, such as a 401. These codes and their text descriptions can be found on the HttpWebResponse property available on WebException.Response if the WebException.Status property is one that contains a response.
Other commonly used classes at the HTTP level include the WebProxy and GlobalProxySelection classes for specifying the use of HTTP proxy servers. The NetworkCredential and CredentialCache classes associate credentials with a request, and the Cookie class manipulates HTTP cookies.
In addition to HTTP schemes, version 1.1 of the .NET Framework supports resolution of FILE: URIs. This functionality is contained in the FileWebRequest and FileWebResponse classes. These classes follow the same request-response model as HttpWebRequest and HttpWebResponse. However, they are fairly thin wrappers over the File class found in the System.IO namespace. FileWebRequest and FileWebResponse have been provided for convenience so that developers working with the FILE: URI scheme do not have to use a different model from that used when resolving HTTP URIs.
Create a new CLR console application and you can use HttpChap6CP as the project and solution names if you want.
![]() |
|
Add the following code.
// HttpChap6CP.cpp : main project file. /// <summary> /// This example demonstrates the use of HttpWebRequest by /// downloading the contents of a URL and displaying them on the console. /// </summary>
#include "stdafx.h"
using namespace System; using namespace System::IO; using namespace System::Net; using namespace System::Text;
[STAThread] int main(array<System::String ^> ^args) { // Validating the input values if (args->Length < 1) { // Console::WriteLine("Usage: {0} URL", Environment::CommandLine); Console::WriteLine("Usage: Executable_file_name URL"); Console::WriteLine("Example: Executable_file_name http://contoso.com/"); Console::WriteLine("Example: Executable_file_name http://youtube.com/"); // Return to OS return 0; } String^ URL = args[0];
try { // Create the request object Console::WriteLine("Creating the request object..."); HttpWebRequest^ request = (HttpWebRequest^)WebRequest::Create(URL);
// Optionally, you can set HTTP-specific elements on // the request, such as the User-Agent header Console::WriteLine("Requet something specific..."); request->UserAgent = "Test Client version 1.0";
// Issue the request Console::WriteLine("Issuing the request..."); HttpWebResponse^ response = (HttpWebResponse^)request->GetResponse(); Console::WriteLine("GetResponse() is OK...");
// Read the content Console::WriteLine("Creating StreamReader to read the content..."); StreamReader^ reader = gcnew StreamReader(response->GetResponseStream(), Encoding::ASCII); String^ content = reader->ReadToEnd(); Console::WriteLine("ReadToEnd() is OK...");
// Display the content to the console Console::WriteLine("Displaying the content to the console...\n"); Console::WriteLine(content); Console::WriteLine("WriteLine() is OK...");
// Close the response Console::WriteLine("Closing the response..."); response->Close(); Console::WriteLine("Close() is OK..."); } catch (WebException^ wex) { Console::WriteLine(wex->ToString()); // Check the status to see if there might be a response object if (wex->Status == WebExceptionStatus::ProtocolError) { HttpWebResponse^ response = (HttpWebResponse^)wex->Response; Console::WriteLine(); Console::WriteLine("The protocol error returned was '" + response->StatusCode.ToString() + "'."); response->Close(); } } return 0; } |
Build and run the project. The following is the output sample.