Search code examples
c#.netstreamwebclientflush

WebClient openWrite not writing until it is closed


I'm using a WebClient to send raw bytes to a web server. The web server knows what to do with those raw bytes. However the WebClient doesn't actually send the data to the server until the call to w.Close() on the last line. I would like to send the data every time w.Flush() is called. Is that possible?

        string filename = "C:\\blah.dat";
        byte[] content = File.ReadAllBytes(filename);

        WebClient wc = new WebClient();
        Stream w = wc.OpenWrite("http://localhost:80/files/");

        for (int i = 1; i < 10; i++)
        {
            w.Write(content, 0, content.Length);
            w.Flush();
        }

        w.Close();

p.s I'm not interested in UploadFile. I'm just using the file's byte[] as sample binary data.


Solution

  • The default behavior of HttpWebClient is to buffer all the data, determine its length and use that to set the Content-Length in HTTP request headers.

    For most people, the correct answer nowadays is to use HttpClient which was introduced in .NET framework 4.5.

    For those of us still using .NET framework v3.5, here are two alternatives:

    • Set the Content-Length before opening the request stream. This cannot be done directly through WebClient, and we need to create the HttpWebRequest object manually. This code sends data byte-per-byte as an example:
    byte[] data = ...;
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://example.com");
    req.Method = "POST";
    req.ContentType = "text/plain";
    req.ContentLength = data.Length;
    Stream stream = req.GetRequestStream();
    for (int i = 0; i < data.Length; i++)
    {
        stream.Write(data, i, 1);
        stream.Flush()
        Thread.Sleep(100);
    }
    stream.Close();
    
    • Set SendChunked to true in HttpWebRequest to use the chunked transfer encoding. Be aware that it has some bugs which affect the bufferOffset argument to stream Write() method.