38

Code exemple:

HttpWebRequest request =
   (HttpWebRequest)HttpWebRequest.Create("http://some.existing.url");

request.Method = "POST";
request.ContentType = "text/xml";

Byte[] documentBytes = GetDocumentBytes ();


using (Stream requestStream = request.GetRequestStream())
{
   requestStream.Write(documentBytes, 0, documentBytes.Length);
   requestStream.Flush();
   requestStream.Close();
}

When I do request.GetRequestStream (), there's nothing to send in the request. From the name of the method, and the intellisense it shows ("Get System.IO.Stream to use to write request data"), nothing indicates that this line of code will connect to the distant server.
But it seems it does...

Can anyone explain to me what HttpWebRequest.GetRequestStream () exactly does ?

Thanks for your enlightenments.

Johnny5
  • 6,664
  • 3
  • 45
  • 78

2 Answers2

25

Getting the request stream does not trigger the post, but closing the stream does. Post data is sent to the server in the following way:

  1. A connection is opened to the host
  2. Send request and headers
  3. Write Post data
  4. Wait for a response.

The act of flushing and closing the stream is the final step, and once the input stream is closed (i.e. the client has sent what it needs to the server), then the server can return a response.

mdm
  • 12,480
  • 5
  • 34
  • 53
  • ` System.Net.HttpWebRequest r = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create("http://url.that.does.not.exists"); r.Method = "POST"; r.ContentType = "text/xml"; using (System.IO.Stream bidon = r.GetRequestStream ()) { bidon.Write (new byte [0], 0, 0); bidon.Close (); }` – Johnny5 Mar 16 '11 at 14:44
  • `System.Net.HttpWebRequest r = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create("http://url.that.does.not.exists"); r.Method = "POST"; r.ContentType = "text/xml"; using (System.IO.Stream bidon = r.GetRequestStream ()) { bidon.Write (new byte [0], 0, 0); bidon.Close (); }` This crashes at GetRequestStream, with a dns error. If I replace 'http://url.that.does.not.exists' with 'http://202.122.0.3', assuming that this ip is not reacheable, It crashes when I do the GetResponse . So I assume that at least DNS resolution is done at GetResponseStream. – Johnny5 Mar 16 '11 at 14:53
  • 2
    Ok, sorry for precedent comments, that was way to long and confuse. I understand it that way: 1: at GetResponseStream, the connection is opened. 2: when I close the stream, the request is send. 3: when I GetResponse, if the response is not yet received, it wait for it. Right? – Johnny5 Mar 16 '11 at 15:01
  • 3
    Hey, I know its a late comment, but the original question states that Getting the request tries to connect to the distant server, not trigger the post, so, even if this question is marked as answered, I still have the original author's question: request.GetRequestStream() doesnt indicate that will connect to the distant server, why does it need to? – cnom Jan 02 '17 at 13:28
  • @cnom. Good question. – frenchone Jun 21 '18 at 11:09
9

You use GetRequestStream() to synchronously obtain a reference to the upload stream. It is only after you have finished writing to the stream that the actual request is send.

However, I would suggest that you use the BeginGetRequestStream method instead of GetRequestStream. BeginGetRequestStream performs asynchronously and don't lock the current thread while the stream is being obtained. You pass a callback and a context to the BeginGetRequestStream. In the callback, you can call EndGetRequestStream() to finally grab a reference and repeat the writing steps listed above (for synchronous behavior). Example:

context.Request.BeginGetRequestStream(new AsyncCallback(Foo), context);

public void Foo(IAsyncResult asyncResult)
    {
        Context context = (Context)asyncResult.AsyncState;
        try
        {
            HttpWebRequest request = context.Request;

            using (var requestStream = request.EndGetRequestStream(asyncResult))
            using (var writer = new StreamWriter(requestStream))
            {
                // write to the request stream
            }

            request.BeginGetResponse(new AsyncCallback(ProcessResponse), context);
        }

Be very careful with BeginGetRequestStream. It never times out, thus you must add additional logic to your program to recover from situations where GetRequestStream will throw a timeout exception.

In general, threads are cheap. The async Begin/End methods of HttpWebRequest are only worth using if you will have 10,000 or more concurrent requests; because implementing timeouts is very tricky and error-prone. In general, using BeginGetRequestStream is premature optimization unless you need significant performance gains.

Community
  • 1
  • 1
Genady Sergeev
  • 1,650
  • 9
  • 11
  • 7
    if `HttpWebRequest.GetRequestStream()` is a pure client-side operation, how can it throw a timeout exception ? also, can it ever return null ? – BaltoStar Jun 22 '15 at 23:47