views:

234

answers:

5

I'd like to create my own custom HTTP requests. The WebClient class is very cool, but it creates the HTTP requests automatically. I'm thinking I need to create a network connection to the web server and pass my data over that stream, but I'm unfamiliar with the library classes that would support that kind of thing.

(Context, I'm working on some code for a web programming class that I'm teaching. I want my students to understand the basics of what's happening inside the "black box" of HTTP.)

+3  A: 

Use the WebRequest or WebResponse classes, as required.

If you need to go lower level than these provide, look at the other System.Net.Sockets.*Client classes such as TcpClient.

Oded
+2  A: 

Check out System.Net.Sockets.TcpClient if you want to write your own low level client. For HTTP GET's and POST's you can use the HttpWebRequest and HttpWebResponse classes though.

If you are really masochistic you could go lower than TcpClient and implement your own Socket, see the Socket class.

Wim Hollebrandse
Yikes. The long, long way to a web request.
Joel Etherton
Using TcpClient would also require him to understand the TELNET protocol that Http is built on.
John Saunders
@John: Yet another bonus!
Wim Hollebrandse
@John Saunders: HTTP is NOT built upon Telnet protocol. Despite the fact that one can use telnet client to connect to a web server.
Igor Korkhov
@Igor: I see you're right. I must have been confusing it with FTP.
John Saunders
+2  A: 

In my response to this SO post http://stackoverflow.com/questions/1948552/2005855#2005855 I have included the basics of creating HttpWebRequest and reading response.

Edit: added a code example from the post above

System.Net.HttpWebRequest oReq; 
string sUrl = "http://yoursite/sites/somesite/DocumentLibrary"; 
oReq = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(sUrl); 

oReq.Method = "GET"; 
oReq.Credentials = System.Net.CredentialCache.DefaultCredentials; 
oReq.AllowAutoRedirect = true; 

//now send the request
using (System.IO.StreamWriter oRequest = 
        new System.IO.StreamWriter(oReq.GetRequestStream())) { 
   oRequest.WriteLine(); 
}

//and read all the response
using (System.Net.HttpWebResponse oResponse = oReq.GetResponse()){
  using (System.IO.StreamReader oResponseReader = 
        new System.IO.StreamReader(oResponse.GetResponseStream())){
    string sResponse = oResponseReader.ReadToEnd(); 
  }
}
naivists
-1: Missing `using` blocks for the StreamReader/Writer, and for the response.
John Saunders
@John Saunders: I know that "using" is a good pattern for coding, however - calling close() on a streamreader DOES close the underlying stream and "releases any system resources associated with the reader" (see MSDN for documentation). So - you are wrong if you think I'm leeking something here.
naivists
You are leaking if some of the stuff inbetween throws an exception.
nos
even in an example code? :-)
naivists
@naivists: especially in example code, since someone will copy and paste it! Always set a _good_ example.
John Saunders
Don't worry. Long ago I learned that example code always comes with a "buy be ware" tags. I'd much rather have an imperfect example than nothing at all. Thanks naivists for your time. +1
Jeff
@John, that sounds true. Edited the code to Dispose as needed (however I didn't test it now :-)
naivists
@naivists: I've removed my downvote. My only other concern is the GetRequestStream/GetResponseStream calls, which I'd break out into separate `using` blocks, just out of paranoia that disposing the reader/writer might not dispose the underlying stream.
John Saunders
+7  A: 

To really understand the internals of the HTTP protocol you could use TcpClient class:

using (var client = new TcpClient("www.google.com", 80))
{
    using (var stream = client.GetStream())
    using (var writer = new StreamWriter(stream))
    using (var reader = new StreamReader(stream))
    {
        writer.AutoFlush = true;
        // Send request headers
        writer.WriteLine("GET / HTTP/1.1");
        writer.WriteLine("Host: www.google.com:80");
        writer.WriteLine("Connection: close");
        writer.WriteLine();
        writer.WriteLine();

        // Read the response from server
        Console.WriteLine(reader.ReadToEnd());
    }
}

Another possibility is to activate tracing by putting the following into your app.config and just use WebClient to perform an HTTP request:

<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.Net" tracemode="protocolonly">
        <listeners>
          <add name="System.Net"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="System.Net" value="Verbose"/>
    </switches>
    <sharedListeners>
      <add name="System.Net"
           type="System.Diagnostics.TextWriterTraceListener"
           initializeData="network.log" />
    </sharedListeners>
    <trace autoflush="true"/>
  </system.diagnostics>
</configuration>

Then you can perform an HTTP call:

using (var client = new WebClient())
{
    var result = client.DownloadString("http://www.google.com");
}

And finally analyze the network traffic in the generated network.log file. WebClient will also follow HTTP redirects.

Darin Dimitrov
Awesome example, I look forward to trying it out. This is a great way to visualize what's going on. Thanks
Jeff
+1  A: 

Use WFetch for the demonstration.

As for programming, HttpWebRequest lets you control quite a bit about the request - again if it's for a demonstration I'd use Wireshark to sniff what's going over the wire when you do various tasks with the HttpWebRequest

nos