Search code examples
c#asp.net-mvcdotnet-httpclienthttppostedfilebase

How to pass a file from a form to HttpClient.PostAsync as a MultipartFormDataContent


Have a form that allows users to upload a file. Nothing fancy here. File is catpured as a HttpPostedFileBase by a controller.

Then from a controller that HttpPostedFileBase is sent to a service that wants to forward that file to a WEB API using HTTPClient.

We're using client.PostAsync(url, content) where the content is MultipartFormDataContent where StreamContent is added using an IO FileRead (Stream). Code below.

Problem is that the filepath from the HttpPostedFileBase references the user local machine path and when server is trying to read it it fails with the: Could not find a part of the path 'C:\Users.....' error

Tried palying with Server.MapPath but the file is not saved to a server in this process(maybe it must be?)

Controller

[HttpPost]
public ActionResult uploadFile(HttpPostedFileBase upload, int someID)
{
    FileUploadService.UploadFile(upload, someID);
    return RedirectToAction("Index");
}

Service

 public static bool UploadFile(HttpPostedFileBase file, int itemID)
    {
        using (var content = new MultipartFormDataContent())
        {
            Stream fs = File.OpenRead(file.FileName); //code fails on this line
            content.Add(CreateFileContent(fs, file.FileName, "text/plain"));

            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
            client.DefaultRequestHeaders.Add("Authorization-Token", token);

            var url = String.Format(.....'code removed not important this part is working' );

            var response = client.PostAsync(url, content).Result;
            response.EnsureSuccessStatusCode();
            if (response.IsSuccessStatusCode)
            {
                string responseString = response.Content.ReadAsStringAsync().Result;
                return true;
            }
            else
            {
                return false;
            }
        }
    }

private static StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
    {
        try
        {
            var fileContent = new StreamContent(stream);
            fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
            {
                Name = "UploadedFile",
                FileName = "\"" + fileName + "\""
            };
            fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
            return fileContent;
        }
        catch (Exception ex)
        {
            return null;
        }
    }

Solution

  • On the line that's failing, you're basically saying to open a file from disk on the server, but you haven't saved it there. And luckily you don't need to; you can get the stream directly from the HttpPostedFileBase.

    Just replace this:

    Stream fs = File.OpenRead(file.FileName);
    content.Add(CreateFileContent(fs, file.FileName, "text/plain"));
    

    with this:

    content.Add(CreateFileContent(file.InputStream, file.FileName, "text/plain"));