Library tutorials & articles

Retrieving HTTP content in .NET

POSTing data

As I mentioned earlier POST data is important in Web request applications and getting the data into the proper format for posting can be tricky requiring possibly a fair amount of code. wwHttp abstracts the process with several overloads of the AddPostKey() method which handles the different POST modes: 1 – URLEncoded form variables, 2 – Multi-part form variables and files, 4 – XML or raw POST buffers.The base method looks as shown in Listing 3.

Listing 3: wwHttp::AddPostKey handles POST data

public void AddPostKey(string Key, byte[] Value)
{
  if (this.oPostData == null)
  {
   this.oPostStream = new MemoryStream();
   this.oPostData = new BinaryWriter(this.oPostStream);
  }
 
  if (Key == "RESET")
  {
   this.oPostStream = new MemoryStream();
   this.oPostData = new BinaryWriter(this.oPostStream);
  }

  switch(this.nPostMode)
  {
   case 1:
     this.oPostData.Write(Encoding.GetEncoding(1252).GetBytes(
            Key + "=" +
            System.Web.HttpUtility.UrlEncode(Value) + "&"));
     break;
   case 2:
     this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes(
      "--" + this.cMultiPartBoundary + "\r\n" +
      "Content-Disposition: form-data; name=\"" +Key+
      "\"\r\n\r\n") );
    
     this.oPostData.Write( Value );

     this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes("\r\n") );
     break;
   default:
     this.oPostData.Write( Value );
     break;
  }
}

This method relies on a stream oPostStream to hold the cumulative POST data a user might send to the server. A BinaryWriter object is used to actually write to the stream sequentially without having to count bytes as you have to do with the raw stream.

Next the actual POST data is actually written into the stream using the Write() of the BinaryWriter. Note that this version of AddPostKey() accepts a byte[] input parameter rather than a string so the data can be written in its raw format.

The BinaryWriterWrite() method has overloads that allow for string parameters, however, this didn't work correctly for me as the encoding was screwed up in the output. Instead the code above explicitly performs the translation for any strings (including static strings like the ones for the multipart form vars) from string to byte array, using the proper encoding as discussed previously. Once again, this was tricky to figure out as you can set an encoding on the BinaryWriter, but which didn't appear to have any effect. The code shown above was the only working solution that runs correctly.

There are several overloads to this method. Most importantly is a string version:

public void AddPostKey(string Key, string Value)
{
  this.AddPostKey(Key,Encoding.GetEncoding(1252).GetBytes(Value));
}

which does little more than converting the string into a byte array with the proper encoding. Another version accepts a single POST buffer, which is typically used for XML or binary content.

public void AddPostKey(string FullPostBuffer)
{
  this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes(FullPostBuffer) );
}

This one writes directly to the binary writer.

Finally there's an AddPostFile() method which allows you to POST a file to the server when running with multi-part forms (PostMode=2) to provide HTML file upload capabilities.

Listing 3.1: HTTP file upload method for multi-part forms

public bool AddPostFile(string Key,string FileName)
{
  byte[] lcFile; 

  if (this.nPostMode != 2) {
    this.cErrorMsg = "File upload allowed only with Multi-part forms";
   this.bError = true;
    return false;
  }

  try
  {    
   FileStream loFile = new FileStream(FileName,System.IO.FileMode.Open,
                     System.IO.FileAccess.Read);

   lcFile = new byte[loFile.Length];
   loFile.Read(lcFile,0,(int) loFile.Length);
   loFile.Close();
  }
  catch(Exception e)
  {
   this.cErrorMsg = e.Message;
   this.bError = true;
   return false;
  }

  this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes(
     "--" + this.cMultiPartBoundary + "\r\n" +
     "Content-Disposition: form-data; name=\"" + Key + "\" filename=\"" +
     new FileInfo(FileName).Name + "\"\r\n\r\n") );

  this.oPostData.Write( lcFile );

  this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes("\r\n")) ;

  return true;
}

The AddPost style methods handle collecting POST data before the request is sent. The actual sending occurs in the main GetUrlStream() method of the wwHttp class.

Listing 3.2: Sending the POST data to the server

// *** Deal with the POST buffer if any
if (this.oPostData != null)
{
  Request.Method = "POST";
  switch (this.nPostMode)
  {
   case 1:
     Request.ContentType = "application/x-www-form-urlencoded";
     break;
   case 2:
     Request.ContentType = "multipart/form-data; boundary=" +
                this.cMultiPartBoundary;
     this.oPostData.Write( Encoding.GetEncoding(1252).GetBytes( "--" +
                this.cMultiPartBoundary + "\r\n" ) );
     break;
   case 4:
     Request.ContentType = "text/xml";
     break;
   default:
     goto case 1;
  }
 
  Stream loPostData = Request.GetRequestStream();

  //*** Copy the Memory Stream to the Request Stream
  this.oPostStream.WriteTo(loPostData);

  //*** Close the memory stream
  this.oPostStream.Close();
  this.oPostStream = null;

  //*** Close the Binary Writer
  this.oPostData.Close();
  this.oPostData = null;

  //*** Close Request Stream
  loPostData.Close();
}

This code finalizes the request for POST data by checking whether we've already written something into the POST buffer and if so configuring the POST request by specifying the content type. In the case of multi-part form POST an epilogue string is added to the end of the content.

Writing out the data entails taking the data from the memory stream that holds our accumulated POST data and writing it out to the request stream (loPostData) which actually sends the POST data to the server.

As you can see a lot of things are happening in order to properly POST data to the server and wwHttp takes care of the details for you with no additional code.

Comments

  1. 10 Jul 2007 at 15:29
      if (oReqCookie.Name ==
            oRespCookie.Name)  {
            oReqCookie.Value =
                   oRespCookie.Name;

    Do you mean?








     if (oReqCookie.Name ==
            oRespCookie.Name)  {
            oReqCookie.Value =
                   oRespCookie.Value;




  2. 12 Mar 2007 at 18:57

    You have a paragraph that states:

    "The most common use of delegates is an eventhandler, which uses the delegate to fire events. When the event publisher fires the event method, the delegate that is assigned to handle the event is called and you're event subscriber object then can simply handle the event by implementing a method in your class."

    Unfortunately, for someone trying desparately to learn C#, this sounds like:

    "blah blah blah blah blah blah"

    I'm sorry but could you publish a REAL SIMPLE example and explanation of asynch calls in Asp.net/C#.  I have been all over the web looking for one and they all assume you already know C# so all the delegate calling callback calling method calling delegate calling calling callingcallingcalling.................has just finally gotten on my nerves.

  3. 29 Dec 2006 at 22:27
    I'm just new to c# coming from VB.NET.  This is a great example!  Thanks
  4. 10 May 2006 at 04:30

    hi

    i have similar problem like you (in a previous time) with in using httwebrequest to login in a website... especially how to handle event clicking ex: onkeypress="checklogin()"

    i hope you can help me to solve the problem..

     

    thnx b4

  5. 18 Oct 2005 at 02:51

    hi
    I use httpwebrequest to login into a website (using Networkcrendential). When i got that page i need to click a link. How can we achieve this (axwebbrowser ?) and it contains frames. And also after clicking that menu in second page i have to click a Javascript button. Is there anyway to achieve this.


    Rajesh

  6. 25 Mar 2005 at 00:48
    Your article is very good and your source code is a good start.  It has some cool features but is lacking some good programming practices.  Most noteable is the lack of finally blocks used.  You should try to insure that the Close() method on the WebRequest and WebResponse objects are always closed before the object reference goes out of scope.  You can ensure that happens by placing your code in a try/finally block.

    Also, you should consider having your class implement the IDisposable interface.  And in that implementation clean up, close, and release the resources used by your private variables.
  7. 01 Jan 1999 at 00:00

    This thread is for discussions of Retrieving HTTP content in .NET.

Leave a comment

Sign in or Join us (it's free).

Rick Strahl
AddThis

Related discussion

Related podcasts

  • More jQuery in ASP.NET

    In this episode Chris Brandsma, Rick Strahl, Dave Ward, Bertrand Le Roy, and Scott Koon conclude their discussion of Microsoft's jQuery in ASP.NET announcement1.This episode of the Alt.NET Podcast is brought to you by LLBLGen Pro, the most mature O/R mapper and code generator out there.Are ...

Events coming up

  • Nov 18

    15 Minutes of Fame

    Dresher, United States

    This is a yearly tradition. We select 10 of the favorite speakers from monthly meetings, code camps, and hands on labs. Each one does a 15 minute talk on their favorite .NET technology. This is our 10th anniversary so we plan a gala event with special prizes and refreshments.

We'd love to hear what you think! Submit ideas or give us feedback