How to send a file using HttpClient in C#

By FoxLearn 1/22/2025 2:45:12 AM   5
When working with HTTP requests in C#, one common task is sending files through a POST request.

This can be achieved using HttpClient and MultipartFormDataContent. By adding the file into a MultipartFormDataContent object, you can easily send it as part of the request body.

Sending a Single File

For example, how to send a file using HttpClient in C#:

var filePath = @"C:\file.png";

using (var multipartFormContent = new MultipartFormDataContent())
{
    // Load the file and set the file's Content-Type header
    var fileStreamContent = new StreamContent(File.OpenRead(filePath));
    fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");

    // Add the file to the request
    multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.png");

    // Send the request
    var response = await httpClient.PostAsync("https://localhost:5000/files/", multipartFormContent);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

This code creates a MultipartFormDataContent object and adds a file (file.png) to it. The file is sent to a server via an HTTP POST request. The Content-Type header is set to image/png, which tells the server the type of the file being sent.

The multipart request looks like this:

POST https://localhost:5000/files/ HTTP/1.1
Host: localhost:5000
Content-Type: multipart/form-data; boundary="43a2ed37-1ab7-3731-b2f4-f84bf159648d"
Content-Length: 7279

--43a2ed37-1ab7-3731-b2f4-f84bf159648d
Content-Type: image/png
Content-Disposition: form-data; name=file; filename=file.png; filename*=utf-8''house.png

<bytes>

When adding a file to MultipartFormDataContent, use the Add() method:

public void Add(HttpContent content, string name, string fileName);

This method adds the file to the multipart data, and the StreamContent object will be disposed when MultipartFormDataContent is disposed.

Sending Form Data with Multiple Fields

Often, you need to send additional data along with the file. You can add extra fields to MultipartFormDataContent.

For example, if you want to send a title and a user ID along with the file.

var filePath = @"C:\file.png";

using (var multipartFormContent = new MultipartFormDataContent())
{
    // Add additional fields
    multipartFormContent.Add(new StringContent("1235"), name: "UserId");
    multipartFormContent.Add(new StringContent("Home insurance"), name: "Title");

    // Add the file
    var fileStreamContent = new StreamContent(File.OpenRead(filePath));
    fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
    multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.png");

    // Send the request
    var response = await httpClient.PostAsync("https://localhost:5000/files/", multipartFormContent);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

This sends a multipart request that includes both the title and user ID, as well as the file:

POST https://localhost:5000/files/ HTTP/1.1
Host: localhost:5000
Content-Type: multipart/form-data; boundary="00d235a2-0189-48e1-86d9-0baf70c2879e"
Content-Length: 7519

--00d235a2-0189-48e1-86d9-0baf70c2879e
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=UserId

1235
--00d335a2-0389-48e1-85d9-0daf70c2879e
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=Title

Home insurance
--00d335a2-0389-48e1-85d9-0daf70c2879e
Content-Type: image/png
Content-Disposition: form-data; name=file; filename=file.png; filename*=utf-8''file.png

<bytes>

Sending a File as a Byte Array

If you already have a file in the form of a byte array (perhaps from a database), you can use ByteArrayContent to send it instead of a file stream:

using (var multipartFormContent = new MultipartFormDataContent())
{
    // Add the file as a byte array
    var byteContent = new ByteArrayContent(fileBytesFromDatabase);
    byteContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
    multipartFormContent.Add(byteContent, name: "file", fileName: "file.png");

    // Send the request
    var response = await httpClient.PostAsync("https://localhost:5000/files/", multipartFormContent);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

This will generate a multipart request with the file content being passed as a byte array, rather than as a file stream.

Sending Multiple Files

You can send more than one file in the same request by adding multiple files to the MultipartFormDataContent.

If the web API expects multiple files under the same field name (e.g., "files"), you can add multiple files using the same name parameter:

var filePaths = new string[] { @"C:\file1.png", @"C:\file2.png" };

using (var multipartFormContent = new MultipartFormDataContent())
{
    foreach(var filePath in filePaths)
    {
        var fileName = Path.GetFileName(filePath);

        // Load the file and set the Content-Type header
        var fileStreamContent = new StreamContent(File.OpenRead(filePath));
        fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");

        // Add the file
        multipartFormContent.Add(fileStreamContent, name: "files", fileName: fileName);
    }

    // Send the request
    var response = await httpClient.PostAsync("https://localhost:5000/files/", multipartFormContent);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

This request will look like:

POST https://localhost:5000/files/ HTTP/1.1
Host: localhost:5000
Content-Type: multipart/form-data; boundary="92f8b9da-876f-42ff-8709-84a0b8d0ef08"
Content-Length: 14442

--92f8b9da-876f-42ff-8709-84a0b8d0ef08
Content-Type: image/png
Content-Disposition: form-data; name=files; filename=file1.png; filename*=utf-8''file1.png

<bytes>

--92f8b9da-876f-42ff-8709-84a0b8d0ef08
Content-Type: image/png
Content-Disposition: form-data; name=files; filename=file2.png; filename*=utf-8''file2.png

<bytes>

Alternatively, you can add each file with a unique name parameter, depending on the server’s requirements.

Setting File Content-Type Dynamically

If the file extension is not known in advance, you can dynamically set the Content-Type based on the file’s extension. Here's an example that uses a dictionary to map file extensions to content types:

var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
    [".png"] = "image/png",
    [".jpg"] = "image/jpeg",
    [".gif"] = "image/gif"
};

var filePath = @"C:\file.png";
var extension = Path.GetExtension(filePath);

if (!map.TryGetValue(extension, out string contentType))
{
    throw new Exception("Can't send this type of file");
}

var fileStreamContent = new StreamContent(File.OpenRead(filePath));
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);

By utilizing MultipartFormDataContent, you can send files along with additional form data or multiple files in a single request. Always ensure that the Content-Type for the file is set correctly, especially when working with different file types.