POST StreamContent with Multiple Files - c#

The code snippet below successfully HttpPosts a single file to WebAPI. I'd like expand it to build StreamContent containing multiple files (similar to Fiddler multi-file posts).
I know I should be adding a "boundary" to the StreamContent, but I'm not sure exactly where. I'd like to eventually convert the FileStream/Stream parameters to be a List so I can iterate through the collection and build StreamContent to POST.
Let me know if this post makes any sense. I'd appreciate any suggestions.
Thanks in advance!
public async Task<HttpStatusCode> UploadOrderFile(FileStream imageFileStream, string filename, string contentType = "image/png")
{
JsonApiClient._client.DefaultRequestHeaders.Clear();
var content = new MultipartFormDataContent
{
JsonApiClient.CreateFileContent(imageFileStream, filename, contentType)
};
JsonApiClient._client.DefaultRequestHeaders.Add("Authorization",
" Bearer " + JsonApiClient.Token.AccessToken);
var response = await JsonApiClient._client.PostAsync("api/UploadFile", content);
response.EnsureSuccessStatusCode();
return response.StatusCode;
}
internal static StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"files\"",
FileName = "\"" + fileName + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}
EDIT: I do not have any issues receiving and saving the posted files. The issue lies in creating the StreamContent necessary to post multiple files.

This is a solution that I tried that works for me. Nothing was changed in CreateFileContent. I just simply converted parameters into collections, iterated through each collection, and added new MultiPartFormDataContent out of multiple StreamContent. The boundary was also added to the MultipartFormDataContent object. If you see anything that is inefficient or plain wrong, let me know. Thanks!
public async Task<HttpStatusCode> UploadOrderFile(List<FileStream> imageFileStream, List<string> filename, string salesOrderNo, List<string> contentType)
{
JsonApiClient._client.DefaultRequestHeaders.Clear();
var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
var content = new MultipartFormDataContent(boundary);
for (var i = 0; i < imageFileStream.Count; i++)
{
content.Add(JsonApiClient.CreateFileContent(imageFileStream[i], filename[i], contentType[i]));
}
JsonApiClient._client.DefaultRequestHeaders.Add("Authorization",
" Bearer " + JsonApiClient.Token.AccessToken);
var response = await JsonApiClient._client.PostAsync("api/UploadFile", content);
response.EnsureSuccessStatusCode();
return response.StatusCode;
}
internal static StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"files\"",
FileName = "\"" + fileName + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}

Try this approach
public HttpResponseMessage Post()
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach(string file in httpRequest.Files)
{
var content = new MultipartFormDataContent
{
JsonApiClient.CreateFileContent(postedFile.InputStream, postedFile.FileName, postedFile.ContentType)
};
// NOTE: To store in memory use postedFile.InputStream
}
return Request.CreateResponse(HttpStatusCode.Created);
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
internal static StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"files\"",
FileName = "\"" + fileName + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}

Related

Cant correct upload file it says no file found for upload

im trying to create method who can upload file from special path to API link, but when i run application its says no file for upload has been added, so i cant understand, where is problem, i think maybe this line is not working correct bellow
requestUploadFileToDocument.GetRequestStream().Write(data, 0, data.Length);
My full code for method
var ConKey = ConfigurationManager.AppSettings["ConKey"];
var AddFile = ConfigurationManager.AppSettings["AddFile"];
var Document_IDSTflow = ConfigurationManager.AppSettings["Document_IDSTflow"];
var file = ConfigurationManager.AppSettings["file"];
string UploadFileToDocumentUrl = String.Format(AddFile + "Document_ID=" + Document_IDSTflow + "&key=" + ConKey);
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] data = encoder.GetBytes(file);
HttpWebRequest requestUploadFileToDocument = WebRequest.Create(UploadFileToDocumentUrl) as HttpWebRequest;
requestUploadFileToDocument.Method = "POST";
requestUploadFileToDocument.ContentType = "multipart/form-data";
requestUploadFileToDocument.ContentLength = data.Length;
requestUploadFileToDocument.GetRequestStream().Write(data, 0, data.Length);
var httpResponse = (HttpWebResponse)requestUploadFileToDocument.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result2 = streamReader.ReadToEnd();
DocumentInfo DocumentInfoJsonData = JsonConvert.DeserializeObject<DocumentInfo>(result2);
if (DocumentInfoJsonData.Status.IsRequestSuccessful == true)
{
Console.WriteLine("Metode (POST) - OK");
}
else
{
Console.WriteLine("Metode (POST) - ERROR");
Console.WriteLine("\n" + "Error info: " + result2 + "\n");
}
}
Okey, i resolve this by my self after some wasted days :D
HttpClient client = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("fileToUpload");
form.Add(content, "fileToUpload");
var stream = new FileStream(FileLocation, FileMode.Open);
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = DocName,
FileName = FileNameExtension
};
form.Add(content);
HttpResponseMessage response = null;
response = client.PostAsync(UploadFileToDocumentUrl, form).Result;

xamarin post not making it to api

Hi my xamarin post is not making it to my rest api.I keep getting "An error occure while sending the request" all my other posts work but just not this one. I have set network permissions as my login and geting data works. any help would be great. below is a code snippet.
public async Task<string> PostChecklist(string json)
{
try
{
JToken rootObject = JObject.Parse(json);
HttpClient httpClient = new HttpClient();
MultipartFormDataContent multipartContent = new MultipartFormDataContent();
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + TokenId);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
string sFile = (string)rootObject["Answers"]["Signature"];
//Get file
if (!File.Exists((string)rootObject["Answers"]["Signature"]))
{
return "no signature found";
}
FileStream fs = File.OpenRead((string)rootObject["Answers"]["Signature"]);
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent, "signature", "signature.png");
#region Upload images
JToken jobectImages = rootObject["Images"];
foreach (var item in jobectImages)
{
foreach (var internalitem in item)
{
foreach (var imageGroup in internalitem)
{
foreach (JObject image in imageGroup)
{
JToken tokenName, tokenFileName;
image.TryGetValue("FileName", out tokenName);
image.TryGetValue("FilePath", out tokenFileName);
string FileName = tokenName.ToString();
string FilePath = tokenFileName.ToString();
//Get file
FileStream fs2 = File.OpenRead(FilePath);
StreamContent streamContent2 = new StreamContent(fs);
streamContent2.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent2, FileName, FileName);
}
}
}
}
#endregion
var contentJson = new StringContent(json);
contentJson.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "JSONString"
};
var contentLong = new StringContent("26");
contentLong.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "Long"
};
var contentLat = new StringContent("96");
contentLat.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "Lat"
};
multipartContent.Add(contentJson);
multipartContent.Add(contentLong);
multipartContent.Add(contentLat);
var response = await httpClient.PostAsync(GlobalVariables.url + "/checkurl/answers/v12", multipartContent).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
Information = await response.Content.ReadAsStringAsync();
JObject jsonOther = JObject.Parse(Information);
if(((String)jsonOther["status"]) == "success")
{
return "";
}
else
{
return (String)jsonOther["message"];
}
}
else{
return "Server Error";
}
}
catch(Exception e)
{
return e.ToString();
}
}
Cool Looks like there was a problem with one of my MultipartFormDataContent when trying to attach images, if i dont attach an image it does work, so the Url post was breaking. Simulator cant take images so never had the problem.. Thanks anyways
MultipartFormDataContent has a bug with how it generates request content based on the order the headers and body are added.
For example
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent, "signature", "signature.png");
Will cause the content type header to be added before the content disposition header,
-----------------------------some boundary value here
Content-Type: application/octet-stream
Content-Disposition: form-data; name=signature; filename=signature.png
which is known to cause issues with how some servers read the body/content of the request
Instead make sure to set the content composition header first and also make sure that the name and file name are wrapped in double quotes before adding it to the multi-part form data content
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = "\"signature\"",
Filename = "\"signature.png\""
};
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent);
The same will need to be done for the other section where images are added
//Get file
FileStream fs2 = File.OpenRead(FilePath);
StreamContent streamContent2 = new StreamContent(fs);
streamContent2.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = string.Format("\"{0}\"", FileName),
Filename = string.Format("\"{0}\"", FileName),
};
streamContent2.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent2);

Python code to c# .net for HTTP Post to API

I need help converting the follow Python code to c# .net. This code is posting/uploading a text file to a webserver. The Python script has been tested and works. I have tried a few solutions with HTTPClient and WebRequest with no luck. Any guidance will be greatly appreciated.
# request a session
client = requests.session()
# Establish the URL
newurl = 'https://localhost/filedist/upload/'
source_file = 'data/test.txt'
headers = {'Authorization': 'Token MYTOKEN'}
# Populate the values with our environment and target path
values = dict(environment='dev', path='Business/Tools')
files = dict(file=open(source_file, 'rb'))
r = client.post(newurl, files=files, data=values, headers=headers)
Here is my latest attempt, which currently is getting a 'Forbidden' error.
public static async Task<string> UploadFile(string path, string fileName)
{
var client = new HttpClient();
string NewURL = "https://localhost/filedist/upload/";
string SourceFile = path;
var content = new MultipartFormDataContent();
client.DefaultRequestHeaders.Add("Authorization", "Token MYTOKEN");
Stream fs = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
content.Add(CreateFileContent(fs, fileName, "text/plain"));
var parameters = new Dictionary<string, string> { { "environment", "dev" }, { "path", "Business/Tools" } };
content.Add(new FormUrlEncodedContent(parameters));
var response = await client.PostAsync(NewURL, content);
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;
}
}
Thanks
I am not 100% on this, but I don't think you can set the authorization header that way. Try using the client authorization header type.
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Token", "MYTOKEN");

Uploaded file always with size zero

I am trying to upload the file to web API so I have the following code
public async Task<Token> upload(string fullMd5, IEnumerable<HttpPostedFileBase> files)
{
string uploadUrl = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// Call CMS API
string jsonContent = string.Empty;
HttpClientHandler handler = new HttpClientHandler();
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
var filesData = new MultipartFormDataContent();
foreach (var item in files)
{
HttpContent filecontent = new StreamContent(item.InputStream);
filecontent.Headers.ContentType = new MediaTypeHeaderValue(item.ContentType);
filecontent.Headers.ContentLength += item.InputStream.Length;
filecontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("multipart/form-data")
{
Name = "file",
FileName = item.FileName,
};
content.Add(filecontent);
}
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + userObj.access_token);
client.DefaultRequestHeaders.Add("Api-version", "2.4");
client.DefaultRequestHeaders.Add("CMSId", UserId);
var response = await client.PostAsync(uploadUrl, content);
jsonContent = await response.Content.ReadAsStringAsync();
}
}
var result = JsonConvert.DeserializeObject<Token>(jsonContent);
return result;
}
}
the API receive the files but corrupted with zero size , the API works well as I tested using postman , I tried to save the files before sending using SaveAs and it worked well any problem in how I send the file
Try using postAsync like this with these headers
using (var client = new HttpClient(handler) {BaseAddress = new Uri(_host)})
{
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(fileInfo.OpenRead());
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
Name = "\"file\"",
FileName = "\"" + fileInfo.Name + "\""
};
fileContent.Headers.ContentType =
MediaTypeHeaderValue.Parse(MimeMapping.GetMimeMapping(fileInfo.Name));
var folderContent = new StringContent(folderId.ToString(CultureInfo.InvariantCulture));
requestContent.Add(fileContent);
requestContent.Add(folderContent, "\"folderId\"");
var result = client.PostAsync("Company/AddFile", requestContent).Result;
}

Post string and bytearray to server

I have done POSTING and GETing from server using string post data, but now i have the next WebService:
submitFeedback(String token, String subject, String body, byte[] photo, byte[] video);
private void PostFeedbackData()
{
if (GS.online != true)
{
MessageBox.Show(GS.translations["ErrorMsg0"]);
}
else
{
HttpWebRequest request = HttpWebRequest.CreateHttp("https://****/feedback");
request.Method = "POST";
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
}
void GetRequestStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
// End the stream request operation
Stream postStream = myRequest.EndGetRequestStream(callbackResult);
// Create the post data
string postData = "";
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
postData = "{\"jsonrpc\": \"2.0\", \"method\": \"getUserSchedule\", \"params\":[" + "\"" + (App.Current as App).UserToken + "\",\"" + FeedbackTitle.Text + "\",\"" + FeedbackContent.Text + "\",\"" + imageBytes + "\"], \"id\": 1}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
myRequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), myRequest);
});
}
Look at post data - it is a string, i can't place there imageBytes array. How to do it?
Is there any reason for using HttpWebRequest ?
I am asking that because i think that the correct way of sending files to a service is by multipartform data. With HttpWebRequest you have to manually implement that.
Here is an example that is using Microsoft's HttpClient that might work for you:
public async Task<string> submitFeedback(String token, String subject, String body, byte[] photo, byte[] video) {
var client = new HttpClient();
var content = new MultipartFormDataContent();
// Some APIs do not support quotes in boundary field
foreach (var param in content.Headers.ContentType.Parameters.Where(param => param.Name.Equals("boundary")))
param.Value = param.Value.Replace("\"", String.Empty);
var tok = new StringContent(token);
content.Add(tok, "\"token\"");
var sub = new StringContent(subject);
content.Add(tok, "\"subject\"");
// Add the Photo
var photoContent = new StreamContent(new MemoryStream(photo));
photoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"photo\"",
FileName = "\"photoname.jpg\""
};
photoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(photoContent);
// Add the video
var videoContent = new StreamContent(new MemoryStream(video));
videoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"video\"",
FileName = "\"videoname.jpg\""
};
videoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("video/mp4");
content.Add(videoContent);
HttpResponseMessage resp;
try {
resp = await client.PostAsync("SERVER_URL_GOES_HERE", content);
}
catch (Exception e)
{
return "EXCEPTION ERROR";
}
if (resp.StatusCode != HttpStatusCode.OK)
{
return resp.StatusCode.ToString();
}
var reponse = await resp.Content.ReadAsStringAsync();
return reponse;
}
Change accordingly.
Note: HttpClient is also using HttpWebRequest under the hood.
Also I don't think its a good idea to have the UI thread making the request. That makes no sense since you are blocking the interface and making the async theory useless.

Categories

Resources