How to send a file with HttpClient in C#
By FoxLearn Published on Mar 11, 2025 176
For example, How to upload a PDF file:
var filePath = @"C:\docs\report.pdf"; using (var multipartFormContent = new MultipartFormDataContent()) { // Load the PDF file and set its Content-Type header var fileStreamContent = new StreamContent(File.OpenRead(filePath)); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); // Add the file to the form data multipartFormContent.Add(fileStreamContent, name: "document", fileName: "report.pdf"); // Send the POST request var response = await httpClient.PostAsync("https://example.com/upload", multipartFormContent); response.EnsureSuccessStatusCode(); // Return the response body as a string return await response.Content.ReadAsStringAsync(); }
This will send the following multipart/form-data
POST request:
POST https://example.com/upload HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary="f7c6bc18-ec75-4f78-bcfd-5b48f5645fc5" Content-Length: 4567 --f7c6bc18-ec75-4f78-bcfd-5b48f5645fc5 Content-Type: application/pdf Content-Disposition: form-data; name=document; filename=report.pdf; filename*=utf-8''report.pdf <bytes>
In this example:
MultipartFormDataContent
: This object is used to store the file content and any other fields that need to be sent as part of the request body.- File Content: The file is read using a
StreamContent
object, and the file's MIME type (application/pdf
) is set explicitly. - Sending the Request:
httpClient.PostAsync()
sends the request to the server, where the file is uploaded.
Sending Additional Fields Along with the File
You can also send extra form data along with the file.
For instance, let's say you want to send the title of the document and the user ID.
var filePath = @"C:\docs\report.pdf"; using (var multipartFormContent = new MultipartFormDataContent()) { // Add extra fields multipartFormContent.Add(new StringContent("987"), name: "UserId"); multipartFormContent.Add(new StringContent("Quarterly report"), name: "Title"); // Add the PDF file var fileStreamContent = new StreamContent(File.OpenRead(filePath)); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); multipartFormContent.Add(fileStreamContent, name: "document", fileName: "report.pdf"); // Send the request var response = await httpClient.PostAsync("https://example.com/upload", multipartFormContent); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }
This would send the following request with the extra fields:
POST https://example.com/upload HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary="3e9b4e5d-d66a-4b06-bc6f-c2a7b32a32f3" Content-Length: 4897 --3e9b4e5d-d66a-4b06-bc6f-c2a7b32a32f3 Content-Type: text/plain; charset=utf-8 Content-Disposition: form-data; name=UserId 987 --3e9b4e5d-d66a-4b06-bc6f-c2a7b32a32f3 Content-Type: text/plain; charset=utf-8 Content-Disposition: form-data; name=Title Quarterly report --3e9b4e5d-d66a-4b06-bc6f-c2a7b32a32f3 Content-Type: application/pdf Content-Disposition: form-data; name=document; filename=report.pdf; filename*=utf-8''report.pdf <bytes>
Sending Multiple Files
If you need to send multiple files in the same request, you can use a similar approach.
For example, How to send multiple PDF files:
var filePaths = new string[] { @"C:\docs\report1.pdf", @"C:\docs\report2.pdf" }; using (var multipartFormContent = new MultipartFormDataContent()) { foreach (var filePath in filePaths) { var fileName = Path.GetFileName(filePath); // Load the file and set its Content-Type header var fileStreamContent = new StreamContent(File.OpenRead(filePath)); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); // Add each file multipartFormContent.Add(fileStreamContent, name: "documents", fileName: fileName); } // Send the request var response = await httpClient.PostAsync("https://example.com/upload", multipartFormContent); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }
This sends the following request with multiple files:
POST https://example.com/upload HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary="bc85c0f7-bf9f-46a1-a876-25f7c6d9f3f4" Content-Length: 10245 --bc85c0f7-bf9f-46a1-a876-25f7c6d9f3f4 Content-Type: application/pdf Content-Disposition: form-data; name=documents; filename=report1.pdf; filename*=utf-8''report1.pdf <bytes> --bc85c0f7-bf9f-46a1-a876-25f7c6d9f3f4 Content-Type: application/pdf Content-Disposition: form-data; name=documents; filename=report2.pdf; filename*=utf-8''report2.pdf <bytes>
Setting the File's Content Type (PDF File Example)
The file "report.pdf" has a content type of "application/pdf", which needs to be explicitly set when sending the file.
// Cached MIME type mappings var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { [".pdf"] = "application/pdf", [".docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document", [".txt"] = "text/plain" }; var filePath = @"C:\docs\report.pdf"; // Extract the file extension var extension = Path.GetExtension(filePath); if (!map.TryGetValue(extension, out string contentType)) { throw new Exception("Can't send this type of file"); } // Read the file as a stream var fileStreamContent = new StreamContent(File.OpenRead(filePath)); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
This sets the Content-Type
header to application/pdf
for the file in the multipart request, like this:
--b60a0be2-f5a8-4723-a566-10fbd4a20d74 Content-Type: application/pdf Content-Disposition: form-data; name=document; filename=report.pdf; filename*=utf-8''report.pdf
In this example:
MIME Type Dictionary: A dictionary is used to map file extensions to their respective MIME types. This helps handle different file types dynamically.
File Extension: We extract the extension of the file using
Path.GetExtension()
and use it to find the correct MIME type from the dictionary.Setting Content-Type: If the extension is found in the dictionary, the corresponding MIME type is used for the
Content-Type
header.
Why Explicitly Set Content-Type?
In many cases, the content type is not automatically set, especially when uploading files. Some web APIs require you to specify the correct MIME type for the file to ensure that the server handles it correctly. If the content type is missing or incorrect, the server might reject the request.
Using FileExtensionContentTypeProvider
.NET provides a built-in class called FileExtensionContentTypeProvider
, which can automatically map file extensions to MIME types. You can use this class instead of manually managing the dictionary if you want to use a comprehensive list of MIME types. This class is part of the Microsoft.AspNetCore.StaticFiles
package.
Example using FileExtensionContentTypeProvider
:
var provider = new FileExtensionContentTypeProvider(); if (!provider.TryGetContentType(filePath, out string contentType)) { contentType = "application/octet-stream"; // Default MIME type if not found } var fileStreamContent = new StreamContent(File.OpenRead(filePath)); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
In this case, the TryGetContentType
method will automatically set the correct content type based on the file's extension.
- Primitive types in C#
- How to set permissions for a directory in C#
- How to Convert Int to Byte Array in C#
- How to Convert string list to int list in C#
- How to convert timestamp to date in C#
- How to Get all files in a folder in C#
- How to use Channel as an async queue in C#
- Case sensitivity in JSON deserialization