HTTPWebRequest
file upload
multipart/form-data
HTTP request
programming

Upload files with HTTPWebrequest multipart/form-data

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Uploading a file with HttpWebRequest and multipart/form-data means building the HTTP body exactly the way a browser would send a form containing a file input. The approach still matters in older .NET Framework code, but for new projects HttpClient is usually simpler, so this pattern is mainly for maintaining or understanding legacy code.

Understand the Multipart Structure

A multipart/form-data request body is split into parts separated by a boundary string. Each part has headers such as Content-Disposition, and file parts usually also include a Content-Type header.

The request must end with a closing boundary. If the boundary format is wrong, many servers will treat the body as malformed even though the raw bytes were sent successfully.

Build the Request Carefully

The core steps are:

  • create a boundary string
  • set ContentType to multipart/form-data; boundary=...
  • write form fields and file bytes to the request stream
  • write the closing boundary
  • read the response

Here is a complete example in C#.

csharp
1using System;
2using System.IO;
3using System.Net;
4using System.Text;
5
6public static class MultipartUploader
7{
8    public static string UploadFile(string url, string filePath, string fieldName)
9    {
10        string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
11        byte[] newLine = Encoding.UTF8.GetBytes("\r\n");
12
13        var request = (HttpWebRequest)WebRequest.Create(url);
14        request.Method = "POST";
15        request.ContentType = "multipart/form-data; boundary=" + boundary;
16
17        using (Stream requestStream = request.GetRequestStream())
18        {
19            string header =
20                "--" + boundary + "\r\n" +
21                "Content-Disposition: form-data; name=\"" + fieldName + "\"; filename=\"" + Path.GetFileName(filePath) + "\"\r\n" +
22                "Content-Type: application/octet-stream\r\n\r\n";
23
24            byte[] headerBytes = Encoding.UTF8.GetBytes(header);
25            requestStream.Write(headerBytes, 0, headerBytes.Length);
26
27            byte[] fileBytes = File.ReadAllBytes(filePath);
28            requestStream.Write(fileBytes, 0, fileBytes.Length);
29            requestStream.Write(newLine, 0, newLine.Length);
30
31            string footer = "--" + boundary + "--\r\n";
32            byte[] footerBytes = Encoding.UTF8.GetBytes(footer);
33            requestStream.Write(footerBytes, 0, footerBytes.Length);
34        }
35
36        using (var response = (HttpWebResponse)request.GetResponse())
37        using (var reader = new StreamReader(response.GetResponseStream()))
38        {
39            return reader.ReadToEnd();
40        }
41    }
42}

This example uploads one file. The same pattern can be extended to include ordinary form fields before the file part.

Add Text Fields When the API Requires Them

Many upload endpoints need metadata alongside the file, such as a title, token, or folder ID. Those values are just additional multipart sections.

csharp
1string fieldPart =
2    "--" + boundary + "\r\n" +
3    "Content-Disposition: form-data; name=\"description\"\r\n\r\n" +
4    "Quarterly report\r\n";

Write that part to the stream before the file part, using the same boundary format.

Stream Large Files Instead of Reading Everything at Once

File.ReadAllBytes is easy to understand, but it loads the full file into memory. For large uploads, stream the file in chunks.

csharp
1using (FileStream fileStream = File.OpenRead(filePath))
2{
3    fileStream.CopyTo(requestStream);
4}

That reduces peak memory usage and is the better pattern for large files or high-throughput upload code.

Prefer HttpClient for New Code

HttpWebRequest still works, but it is older and more verbose than current .NET networking APIs. In new applications, HttpClient with MultipartFormDataContent is usually clearer and less error-prone.

This matters because many multipart bugs in legacy code are not business-logic bugs at all. They are manual request-formatting mistakes that newer APIs avoid.

Common Pitfalls

The most common mistake is formatting the boundary incorrectly or forgetting the closing boundary line.

Another mistake is omitting the required \r\n separators between multipart headers and content.

A third issue is reading the entire file into memory for large uploads when a stream-based approach would be safer.

Finally, some APIs require authentication headers or specific field names. If the server rejects the request, verify the endpoint contract before rewriting the multipart code.

Summary

  • 'multipart/form-data uploads require correctly formatted boundaries, headers, and separators.'
  • With HttpWebRequest, you manually write each multipart section to the request stream.
  • Add form fields as separate parts using the same boundary format.
  • Stream large files instead of loading them fully into memory when possible.
  • Use HttpClient for new code, but understand HttpWebRequest for legacy maintenance.
  • If an upload fails, inspect boundary formatting, field names, and server requirements first.

Course illustration
Course illustration

All Rights Reserved.