Uploading Files in WinForms Using HttpWebRequest with Progress Tracking

Uploading large files directly via WebClient can lead to high memory consumption because the antire file is loaded into memory before transmission. A more efficient approach uses HttpWebRequest to stream data in chunks, allowing for real-time progress updates and better memory management.

Client-Side Implementation (WinForms)

The following method streams a file to a remote server using multipart/form-data. It updates UI controls like ProgressBar and Label to reflect the transfer speed and percentage.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;

public int SendFileToServer(string url, string localPath, string remoteFileName, ProgressBar progressTracker)
{
    int resultStatus = 0;
    FileStream fileStream = new FileStream(localPath, FileMode.Open, FileAccess.Read);
    BinaryReader fileReader = new BinaryReader(fileStream);

    // Generate a unique boundary for the multipart form
    string boundaryId = "----" + DateTime.Now.Ticks.ToString("x");
    byte[] boundaryEnd = Encoding.ASCII.GetBytes("\r\n--" + boundaryId + "--\r\n");

    // Construct the header for the form-data
    StringBuilder headerBuilder = new StringBuilder();
    headerBuilder.AppendLine("--" + boundaryId);
    headerBuilder.AppendLine("Content-Disposition: form-data; name=\"uploadedFile\"; filename=\"" + remoteFileName + "\"");
    headerBuilder.AppendLine("Content-Type: application/octet-stream");
    headerBuilder.AppendLine();

    byte[] headerBytes = Encoding.UTF8.GetBytes(headerBuilder.ToString());

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.AllowWriteStreamBuffering = false; // Stream directly to network
    request.Timeout = 300000; // 5 minutes
    request.ContentType = "multipart/form-data; boundary=" + boundaryId;

    long totalSize = fileStream.Length + headerBytes.Length + boundaryEnd.Length;
    request.ContentLength = totalSize;

    try
    {
        progressTracker.Minimum = 0;
        progressTracker.Maximum = 100; // Percentage based
        progressTracker.Value = 0;

        byte[] buffer = new byte[4096];
        long bytesSent = 0;
        DateTime start = DateTime.Now;
        int bytesRead = fileReader.Read(buffer, 0, buffer.Length);

        using (Stream requestStream = request.GetRequestStream())
        {
            // Write Header
            requestStream.Write(headerBytes, 0, headerBytes.Length);
            bytesSent += headerBytes.Length;

            // Write File Content in chunks
            while (bytesRead > 0)
            {
                requestStream.Write(buffer, 0, bytesRead);
                bytesSent += bytesRead;

                // Update UI
                double percentage = (double)bytesSent / totalSize * 100;
                progressTracker.Value = Math.Min(100, (int)percentage);

                TimeSpan elapsed = DateTime.Now - start;
                if (elapsed.TotalSeconds > 0)
                {
                    double speed = (bytesSent / 1024.0) / elapsed.TotalSeconds;
                    // Update labels (assuming lblSpeed and lblStatus exist)
                    // lblSpeed.Text = $"{speed:F2} KB/s";
                    // lblStatus.Text = $"{percentage:F2}% completed";
                }

                Application.DoEvents(); // Keep UI responsive
                bytesRead = fileReader.Read(buffer, 0, buffer.Length);
            }

            // Write Footer
            requestStream.Write(boundaryEnd, 0, boundaryEnd.Length);
        }

        // Read Server Response
        using (WebResponse response = request.GetResponse())
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            string serverResponse = reader.ReadLine();
            if (serverResponse == "OK")
            {
                resultStatus = 1;
            }
        }
    }
    catch
    {
        resultStatus = 0;
    }
    finally
    {
        fileReader.Close();
        fileStream.Close();
    }
    return resultStatus;
}

Parameters:

  • url: The endpoint handling the upload (e.g., http://localhost/Receiver.aspx).
  • localPath: Full path to the file on disk (e.g., C:\\Data\\archive.zip).
  • remoteFileName: The name the file should have on the server.
  • progressTracker: A WinForms ProgressBar control.

Server-Side Implementation (ASP.NET WebForms)

Create a page (e.g., Receiver.aspx) and handle the file in the Page_Load event. The server reads the multipart data from Request.Files.

protected void Page_Load(object sender, EventArgs e)
{
    if (Request.Files.Count > 0)
    {
        try
        {
            HttpPostedFile uploadedFile = Request.Files[0];
            string serverPath = Server.MapPath("~/Uploads/") + uploadedFile.FileName;
            uploadedFile.SaveAs(serverPath);
            Response.Write("OK");
        }
        catch (Exception)
        {
            Response.Write("Error");
        }
    }
}

Configuration

To support large files, update the <httpRuntime> element in web.config. The default limit is usually 4MB.

<configuration>
  <system.web>
    <httpRuntime maxRequestLength="102400" executionTimeout="300" />
  </system.web>
</configuration>
  • maxRequestLength: Size in KB (e.g., 102400 = 100MB).
  • executionTimeout: Timeout in seconds.

Ensure the IIS site binding also allows to larger request sizes (e.g., via uploadReadAheadSize or maxAllowedContentLength in web.config for IIS 7+).

Tags: C# WinForms HttpWebRequest File Upload Multipart Form Data

Posted on Mon, 28 Sep 2026 16:43:38 +0000 by jateeq