Search code examples
javascriptc#filestream

How to set FileType on filestream


I'm trying to send a file stream from c# to my js backend. The name and path get send over correctly but the type seems to be missing when I log the file that enters my backend and I absolutely need the filetype but I can't figure out how to pass it with. can someone help me with this please?

object that comes in:

File {
  _events: [Object: null prototype] {},
  _eventsCount: 0,
  _maxListeners: undefined,
  size: 13920,
  path: '/var/folders/5g/f343vctd6hd7smyd5ybnfp4m0000gn/T/upload_4aebdbbee06344e12d8566dd706fd1e6',
  name: 'Invoice19.pdf',
  type: null,
  hash: null,
  lastModifiedDate: 2020-03-17T14:11:04.812Z,
  _writeStream: WriteStream {
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: true,
      needDrain: false,
      ending: true,
      ended: true,
      finished: true,
      destroyed: true,
      decodeStrings: true,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: false,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      bufferedRequest: null,
      lastBufferedRequest: null,
      pendingcb: 0,
      prefinished: true,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: false,
      bufferedRequestCount: 0,
      corkedRequestsFree: [Object]
    },
    writable: false,
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    path: '/var/folders/5g/f343vctd6hd7smyd5ybnfp4m0000gn/T/upload_4aebdbbee06344e12d8566dd706fd1e6',
    fd: null,
    flags: 'w',
    mode: 438,
    start: undefined,
    autoClose: true,
    pos: undefined,
    bytesWritten: 13920,
    closed: false
  }
}

my c# code

 public IAsyncResult BeginExecute()
        {
            // set authentication
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", BearerToken);
            string url = "http://12915520.ngrok.io/api/organisations/" + OrganisationId + "/projects/" + ProjectId + "/process";
            string response = null;
            bool succesfullRequest = false;
            try
            {
                using (FileStream fs = File.Open(@"C:\Users\X Y\Downloads\Invoice19.pdf", FileMode.Open, FileAccess.Read))
                {
                    // send the content to the backend, parse results
                    HttpContent content = new StreamContent(fs);

                    MultipartFormDataContent formdata = new MultipartFormDataContent();
                    formdata.Add(content, "files", "Invoice19.pdf");
                    var result = client.PostAsync(url, formdata).Result;
                    response = result.Content.ReadAsStringAsync().Result;
                    succesfullRequest = result.IsSuccessStatusCode;
                }
            }
            // I absolutely want to catch every exception and pass these along to the workflow
            catch (Exception ex)
            {
                ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                throw;
            }
            // if something went wrong in the backend, throw an error
            if (!succesfullRequest)
            {
                throw new Exception("Something went wrong during the upload process");
            }

            UploadResponse r = JsonConvert.DeserializeObject<UploadResponse>(response);
            Console.WriteLine("uploadresponse:" + r.ToString());

            // dirty solution: since we don't know how long the pipeline needs to process the upload, we'll be polling for a result
            // since this is a poc this is a temporary solution, if this gets released this needs to be rewritten (maybe with webhooks)
            //var polling = true;
            //do
            //{
            //    response = client.GetAsync(url + "/" + r.uploadId).Result.Content.ReadAsStringAsync().Result;
            //    if (response != "null")
            //    {
            //        polling = false;
            //    }
            //} while (polling);
            // Because we know that there is a response now, actually execute the request
            //return client.GetAsync(url + "/" + r.uploadId);
            return null;
        }

Solution

  • I got it working by doing this:

                    MultipartFormDataContent formdata = new MultipartFormDataContent()
                    foreach (var filePath in Files.Get(context))
                    {
                        // create filestream content
                        FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        HttpContent content = new StreamContent(fs);
                        string name = GetFileName(filePath);
                        content.Headers.Add("Content-Type", GetFileType(name));
                        formdata.Add(content, "files", name);
                    }
                    // send content to the backend and parse result
                    var resultPost = client.PostAsync(url, formdata).Result;
                    response = resultPost.Content.ReadAsStringAsync().Result;
                    succesfullRequest = resultPost.IsSuccessStatusCode;
    

    Basically, I set the content type of my inner content to whatever filetype it is and then set the content-type of my outer content to multipart/form-data (by adding it to the MultiPartFormData)

    since I only support a limited amount of file types, I was able to write a simple function:

            private string GetFileType(string name)
            {
                char[] charSeparators = new char[] { '.' };
                var splitName = name.Split(charSeparators);
                string extension = splitName[1].ToLower();
                switch (extension)
                {
                    case "pdf":
                        return "application/pdf";
                    case "png":
                        return "image/png";
                    case "doc":
                        return "application/msword";
                    case "docx":
                        return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
                    case "txt":
                        return "text/plain";
                    case "tif":
                        return "image/tif";
                    case "jpg":
                        return "image/jpg";
                    case "rtf":
                        return "application/rtf";
                    // default == not supported type, we don't set content type
                    default:
                        return "";
                }
            }