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;
}
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 "";
}
}