Search code examples
c#restdotnet-httpclientmultipart

How to split an HTTP Request Body in two parts?


I'm fairly new to use HTTPClient and sending REST requests to APIs, I'm currently practicing multipart upload using this Google Drive API endpoint:

POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart

There's an instruction that states there to split the request body into two parts, I tried to recreate this but was unable to do so.

https://developers.google.com/drive/api/guides/manage-uploads#multipart

Here's my current code:

async void UploadFile(StorageFile fileName)
{
    using (HttpClient client = new HttpClient())
    {
        // Opens files and convert it to stream
        var resultStream = await fileName.OpenReadAsync();
        var fileStreamContent = new StreamContent(resultStream.AsStream());

        // Create file MetaData
        var fileMetaData = JsonConvert.SerializeObject(
                            new { name = fileName.Name,  mimetype = fileName.ContentType });

        // Create POST request
        var requestMessage = new HttpRequestMessage(HttpMethod.Post, uploadFileEndpoint);
        requestMessage.Headers.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
        // Add request body
        requestMessage.Content = new StringContent(fileMetaData, Encoding.UTF8, "application/json");
        requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/related");

        var response = await client.SendAsync(requestMessage);
        string responseString = await response.Content.ReadAsStringAsync();
        output(responseString);
    }
}

Any help would be greatly appreciated, thank you!


Solution

  • According to the documentation on Perform a multipart upload (HTTP tab), you need the MultipartFormDataContent as suggested by @Jeremy.

    There are a few things needed to perform/migrate:

    1. Add AuthenticationHeaderValue into client.DefaultRequestHeaders.Authorization.

    2. Create a StreamContent instance, fileStreamContent (which you have done) and specify its Headers.ContentType.

    3. Create a StringContent instance, stringContent (which you have done).

    4. Append both StreamContent and StringContent into the MultipartFormDataContent instance, formData.

    5. Specify the formData's Headers.ContentType as requested in API docs.

    6. Post the formData with await client.PostAsync(/* API Url */, formData);

    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
    
        // Opens files and convert it to stream
        var resultStream = await fileName.OpenReadAsync();
        var fileStreamContent = new StreamContent(resultStream.AsStream());
                    
        fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue(fileName.ContentType);
    
        // Create file MetaData
        var fileMetaData = JsonConvert.SerializeObject(new { name = fileName.Name, mimetype = fileName.ContentType });
        var stringContent = new StringContent(fileMetaData, Encoding.UTF8, "application/json");
    
       // Create POST request
       MultipartFormDataContent formData = new MultipartFormDataContent();
       formData.Add(stringContent, "metadata");
       formData.Add(fileStreamContent, "media");
    
       formData.Headers.ContentType = new MediaTypeHeaderValue("multipart/related");
    
       var response = await client.PostAsync(uploadFileEndpoint, formData);
       string responseString = await response.Content.ReadAsStringAsync();
    }