Multi File sending with HttpClient multipart/form-data - c#

I'm trying to post a multipart/form-data Using HttpClient
the form requires a certain number of images.
Code :
var client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
var postData = new List<KeyValuePair(string,string)> ();
postData.Add(new KeyValuePair < string, string > ("function", "picture2"));
postData.Add(new KeyValuePair < string, string > ("username ", UserID));
postData.Add(new KeyValuePair < string, string > ("password ", Password));
foreach(var keyValuePair in postData) {
content.Add(new StringContent(keyValuePair.Value),
String.Format("\"{0}\"", keyValuePair.Key));
}
int x = 1;
foreach(Bitmap item in newpics) {
using(MemoryStream ms = new MemoryStream()) {
item.Save(ms, ImageFormat.Bmp);
byte[] bits = ms.ToArray();
content.Add(new ByteArrayContent(bits), '"' + "pict" + x + '"');
x += 1;
}
}
The problem is that only the last image is delivered !!
why does this happen?? what did i miss? and how to fix this problem?
Thanks in advance..

This is an example of how to post string and file stream with HTTPClient using MultipartFormDataContent. The Content-Disposition and Content-Type need to be specified for each HTTPContent:
Here's my example. Hope it helps:
var path = #"C:\B2BAssetRoot\files\596086\596086.1.mp4";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service");
using (var content = new MultipartFormDataContent())
{
string assetName = Path.GetFileName(path);
var request = new HTTPBrightCoveRequest()
{
Method = "create_video",
Parameters = new Params()
{
CreateMultipleRenditions = "true",
EncodeTo = EncodeTo.Mp4.ToString().ToUpper(),
Token = "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg..",
Video = new Video()
{
Name = assetName,
ReferenceId = Guid.NewGuid().ToString(),
ShortDescription = assetName
}
}
};
//Content-Disposition: form-data; name="json"
var stringContent = new StringContent(JsonConvert.SerializeObject(request));
stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
content.Add(stringContent, "json");
FileStream fs = File.OpenRead(path);
var streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
//Content-Disposition: form-data; name="file"; filename="C:\B2BAssetRoot\files\596090\596090.1.mp4";
streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\"");
content.Add(streamContent, "file", Path.GetFileName(path));
//content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
Task<HttpResponseMessage> message = client.PostAsync("http://api.brightcove.com/services/post", content);
var input = message.Result.Content.ReadAsStringAsync();
Console.WriteLine(input.Result);
Console.Read();

Related

How to CREATE POST IN C# to an endpoint on BMC REMEDY API to create a ticket with files submited in form-data?

I have this problem. i have to submit a file (or not) to an endpoint on an API of bmc.
the KEY:entry with the VALUE:data_entry.txt is the json to send with the values, as the same of the body.
The attach-z2AF_WIAttachment1 is the file i want to submit. I'm it's always throuwing some error, or headers invalid, or filetype not valid, but in postman is working.
I cant convert to C#.
this is my code so far, or now.
try
{
//authentication
var dict = new Dictionary<string, string>();
dict.Add("username", "applicationUsernameJonDoe");
dict.Add("password", "applicationPassowrdXPTO");
var clientLogin = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, Endpoint_loginITSM) { Content = new FormUrlEncodedContent(dict) };
var res = clientLogin.SendAsync(req); //.Result.ToString();
var body = res.GetAwaiter().GetResult().Content.ReadAsStringAsync();
//pedido de criação de registo
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post
};
request.Headers.Add("Authorization", body.Result.ToString());
if (!string.IsNullOrEmpty(registos.Objeto.fileName))
{
registos.Objeto.Registo.z2AF_WIAttachment1 = registos.Objeto.fileName;
}
string json = JsonConvert.SerializeObject(new { values = registos.Objeto });
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
MemoryStream memoryStream = new MemoryStream();
using (BsonDataWriter writer = new BsonDataWriter(memoryStream))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, registos.Objeto.Registo);
}
var data_entry_bytes = memoryStream.ToArray();
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
ByteArrayContent data_entry_json_content = new ByteArrayContent(data_entry_bytes);
data_entry_json_content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
data_entry_json_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("entry")
{
FileName = "data_entry.txt",
Name = "entry",
};
multiForm.Add(data_entry_json_content);
ByteArrayContent z2AF_WIAttachment1_content = new ByteArrayContent(file_bytes);
z2AF_WIAttachment1_content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
z2AF_WIAttachment1_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attach-z2AF_WIAttachment1")
{
FileName = registos.Objeto.fileName,
Name = "attach-z2AF_WIAttachment1",
};
multiForm.Add(z2AF_WIAttachment1_content);
request.Content = multiForm;
var result = await client.SendAsync(request);
var resBody = result.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _resBody = JsonConvert.DeserializeObject<dynamic>(resBody);
string registoID = _resBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", registoID);
}
}
catch (Exception e)
{
string classname = this.GetType().Name;
CentralLibrary.Services.ErrorLoggingService.ErrorLogsForCore(classname, e, _env.WebRootPath);
return ResponseHandler<string>.Resposta(true, "EXCEPTION : resposta api bit criar registos", e.Message);
}
Here is a better solution.
I had a problem with the last, but for someone who doesnt wnat to use de library RestClient that's the way. But this is working 100% and i have JsonProperty Names for NewtonSoft.Json so this workin with names like
[JsonProperty("z1D Action")]
public string z1D_Action { get; } = "CREATE";
so, my code is, and using an object AbrirRegistosITSM with nested object AbrirRegistosITSM_com_anexo my final solution is
AbrirRegistosITSM _registo = new AbrirRegistosITSM
{
Values = new AbrirRegistosITSM_com_anexo
{
Details = registos.Objeto.Comentario,
Customer_Login = registos.username,
Login_ID = registos.username,
SR_Type_Field_3 = registos.Objeto.Tipologia,
SR_Type_Field_28 = registos.Objeto.Categoria,
z2AF_WIAttachment1 = registos.Objeto.FicheiroNome
}
};
var client = new RestClient(Endpoint_CreateITSM);
string baseFolder = _env.WebRootPath;
string pathDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathDir);
string pathDirFile = Path.Combine(pathDir, registos.Objeto.FicheiroNome);
File.WriteAllBytes(pathDirFile, Convert.FromBase64String(registos.Objeto.FicheiroBase64));
string pathEntryDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathEntryDir);
string patnEntrydirFile = Path.Combine(pathEntryDir, "data_entry.txt");
File.WriteAllText(patnEntrydirFile, JsonConvert.SerializeObject(new { values = _registo.Values }));
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Authorization", token);
request.AddFile("entry", patnEntrydirFile, "application/json");
request.AddFile("attach-z2AF_WIAttachment1", pathDirFile, "application/octet-stream");
var reqbody = JsonConvert.SerializeObject(_registo);
request.AddParameter("application/json", reqbody, ParameterType.RequestBody);
RestResponse response = client.Execute(request);
var respostaBody = response.Content.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"]["Request Number"];
then i return the request number that what i need, but you have a lot of values there. I use NewtonSoft remember that. I dont use JsonSerializer because i wasn't able to save the json property names with spaces with JsonSerializer.
I'm not entirely sure what's going wrong here. It can be a lot of things, but I might be able to get you going. The last couple of weeks I build a HttpClient that sends a file with metadata to a GraphQL endpoint.
Please ensure the following:
I think you are requesting the file through an call. Please store it in a variable as a Byte[] using the ReadAsByteArrayAsync(). Do note decode it or cast it to a string or anything. You'll just corrupt the file.
var response = client.GetAsync(fileUrl);
var downloadedFile = await response.Result.Content.ReadAsByteArrayAsync();
The following code might not work entirely in your case, but should help you get going building the right request, since I'm also sending metadata in my request containing the file extension and some other information. This will most likely send the file to your API without a file extension.
using (var client = new HttpClient())
{
var file = new byte[] { 1, 2, 3 };
var fileToUpload = new ByteArrayContent(file);
var formData = new MultipartFormDataContent
{
{ fileToUpload, "entry", "passInFileExtensionForExample"},
{ fileToUpload, "attach-z2AF_WIAttachment1", "passInFileExtensionForExample" }
};
var response = await client.PostAsync("endpoint", formData);
}
Add the Bearer token using the following code:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
So i've discover the solution for my problem. I'm gonna to submit only one file. I have to submit also the Json body as a file "entry" "data_entry.txt" and for HttpRequestMessage you have to have a content MultipartFormDataContent and here you can add as many files as you have. i have to convert the Json body to a file ( in this case i converted to binary Array) with the name entry, and the name of the file data_entry.txt, but it's what the endpoint needs, so...whatever.
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
MultipartFormDataContent content = new MultipartFormDataContent();
//adicionar ficheiro
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
StreamContent fileContent = new StreamContent(new MemoryStream(file_bytes));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[attach-z2AF_WIAttachment1]",
FileName = registos.Objeto.fileName
};
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
content.Add(fileContent);
//adicionar ficheiro entry
StreamContent entryStreamContent = new StreamContent(new MemoryStream(ObjectToByteArray(registos.Objeto.Registo)));
entryStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[entry]",
FileName = "data_entry.txt"
};
entryStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
content.Add(entryStreamContent);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post,
Content= content
};
request.Headers.Add("Authorization", body.Result.ToString());
string json = JsonConvert.SerializeObject(new { values = registos.Objeto.Registo});
request.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(json));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var resposta = await client.SendAsync(request);
var respostaBody = resposta.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", _registoID);
So this is my solution. and it's working :)

POST result empty after passing a JSON string along with a file

I'm encountering an issue uploading a file (image for this example) along with a JSON string. I am as the client, trying to upload to a webserver. Currently on the website itself, when uploading a file, the payload is this:
------WebKitFormBoundary1A4Toq4hnrayCRu4
Content-Disposition: form-data; name="FileInstance"
{"action":["/public/my_folder"],"fileName":"download_icon.png","fileSize":313,"certification":{"level":"0","Groups":[]}}
------WebKitFormBoundary1A4Toq4hnrayCRu4
Content-Disposition: form-data; name="download_icon.png"; filename="download_icon.png"
Content-Type: image/png
------WebKitFormBoundary1A4Toq4hnrayCRu4--
I am POSTing by 2 separate requests, and each result has a 200 status code, but looking into the result, it's empty and I should be receiving an md5hash of the file uploaded but I am not.
Here is my code:
// Uploading the JSON first
MultipartFormDataContent form = new MultipartFormDataContent();
var boundary = $"----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
form.Headers.Remove("Content-Type");
form.Headers.Add("Content-Type", $"multipart/form-data; boundary={boundary}");
MyFileClass currentFile = new MyFileClass();
currentFile.action = new List<string>() { "/public/my_folder" };
currentFile.filename = Path.GetFileName(Filename);
currentFile.fileSize = Convert.ToInt32(new FileInfo(Filename).Length);
currentFile.certification= new MyFileClass.Certification();
CreateCertification(currentFile.certification);
var json = JsonConvert.SerializeObject(currentFile);
HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = Path.GetFileName(Filename),
FileName = Path.GetFileName(Filename)
};
var response = await myHttpClient.PostAsync(url, form);
var result_str = response.Content.ReadAsStringAsync().Result;
// Uploading the actual file
var stream = new FileStream(Filename, FileMode.Open);
form = new MultipartFormDataContent();
boundary = $"----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
form.Headers.Remove("Content-Type");
form.Headers.Add("Content-Type", $"multipart/form-data; boundary={boundary}");
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "FileInstance"
};
content = new StreamContent(stream);
form.Add(content, Path.GetFileNameWithoutExtension(Filename));
response = await myHttpClient.PostAsync(url, form);
result_str = response.Content.ReadAsStringAsync().Result;
Edit 1: This is how httpclient is defined:
string password = SecureStringExtensions.ToUnsecuredString(Password);
var credCache = new CredentialCache
{
{
new Uri(url), "Basic", new NetworkCredential(Username, password)
}
};
var myHttpClient = new HttpClient(new HttpClientHandler() { Credentials = credCache });
myHttpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
myHttpClient.Timeout = Timeout.InfiniteTimeSpan;
I was trying different methods of POSTing which didn't work. Now I found a solution, where I removed editing the boundary and ContentType, and straight forward added the file and JSON at the same time to MultipartFormDataContent and it worked fine.
MyFileClass currentFile = new MyFileClass();
currentFile.action = new List<string>() { "/public/my_folder" };
currentFile.filename = Path.GetFileName(Filename);
currentFile.fileSize = Convert.ToInt32(new FileInfo(Filename).Length);
currentFile.certification= new MyFileClass.Certification();
CreateCertification(currentFile.certification);
var json = JsonConvert.SerializeObject(currentFile);
var formContent = new MultipartFormDataContent
{
{ new StringContent(json, Encoding.UTF8, "application/json") },
{ new StreamContent(new MemoryStream(File.ReadAllBytes(Filename))), Path.GetFileName(Filename) ,Path.GetFileName(Filename)}
};
var response = await myHttpClient.PostAsync(url, formContent);
string stringContent = await response.Content.ReadAsStringAsync();
Where Filename is the absolute path of the file itself.

Httpclient multipart/form-data pust image

I am trying to send a Put request with binary file to upload to the server, using Httpclient.SendAsync or Httpclient.PutAsync. But all i got is 400 bad request in server response. Here is the code
private static HttpResponseMessage Upload()
{
var apiUri = string.Format(url);
string url = (url);
var message = new HttpRequestMessage();
message.RequestUri = new Uri(apiUri);
message.Method = HttpMethod.Put;
var fileObj = Images.ChooseImageAndToInfoObject();
using (var client = new HttpClient())
using (var content = new MultipartFormDataContent())
{
var filestream = new FileStream(fileObj.filePath, FileMode.Open);
content.Add(new StreamContent(filestream), fileObj.fileName, fileObj.fileNameWithExtension);
content.Add(new StringContent("file"), "withName");
content.Add(new StringContent("string"), "fileName");
content.Add(new StringContent("image/*"), "mimeType");
message.Content = content;
message.Headers.Add("Authorization", MyToken);
// var res = client.SendAsync(message).Result;
var response = client.PutAsync(url, content).Result;
return response;
}
Hope for you, guys
Is it necessary to send the filename and mimetype via multipart-formdata? If not try to send the data as StreamContent and set the filename and mime type via the content header:
private static HttpResponseMessage Upload()
{
var apiUri = string.Format(url);
string url = (url);
var message = new HttpRequestMessage();
message.RequestUri = new Uri(apiUri);
message.Method = HttpMethod.Put;
var fileObj = Images.ChooseImageAndToInfoObject();
using (var client = new HttpClient())
var filestream = new FileStream(fileObj.filePath, FileMode.Open);
var content = new StreamContent(filestream);
content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(fileObj.filePath));
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"files\"",
FileName = "\"" + fileName + "\""
};
message.Content = content;
message.Headers.Add("Authorization", MyToken);
// var res = client.SendAsync(message).Result;
var response = client.PutAsync(url, content).Result;
return response;
Send the content via PUT if you set the file to a specific id or via Post:
var response = client.PostAsync(url, content).Result;

sending the image as a bytes to the web service in Windows Application

I'm working on UWP apps, In that i need to upload the image for that i'm calling the web service to post the details. I'm using the below code to serialize the image.
byte[] fileBytes = null;
using (var stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
docs.Document = fileBytes;
docs.DocumentName = file.Name;
docs.DocumentTypeOtherDescription = "ProfilePicture";
var docsAsJson = JsonConvert.SerializeObject(docs);
StringContent stringContent = new StringContent(docsAsJson, System.Text.Encoding.UTF8);
ByteArrayContent byteContent = new ByteArrayContent(fileBytes);
MultipartFormDataContent httpContent = new MultipartFormDataContent();
httpContent.Add(byteContent, file.Name);
httpContent.Add(stringContent);
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage {Method = HttpMethod.Post};
request.Headers.Add("authorization", App.TokenType + " " + App.AccessToken);
request.RequestUri = new Uri(App.BaseUrl + "api/User/UploadUserDocument");
request.Content = httpContent;
request.Content.Headers.Add(#"Content-Length", fileBytes.Length.ToString());
var response = httpClient.SendAsync(request).Result;
var data = response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
}
}
This is my side to serialize the image and in service side they deserialize the image and saved in database. But i'm getting StatusCode: 500, ReasonPhrase: 'Internal Server Error' this error, Any one please help me to solve this issue.
Here is my Service Code:
public IHttpActionResult UpdateUserWithProfilePic(FormData userviewmodel)
{
var error = string.Empty;
var userJson = new StringBuilder();
foreach (var items in userviewmodel.Fields)
{
if (items.Name == "}")
{
if (!userJson.ToString().EndsWith(",")) continue;
userJson.Remove(userJson.Length - 1, 1);
userJson.Append("}");
}
else
userJson.Append((items.Name.Replace("%22", "\"")) + ":" + items.Value);
}
var userView = JsonConvert.DeserializeObject<UserViewModel>(userJson.ToString());
var result = UpdateUser(userView, error);
if (result.ResultType != ResultType.Success) return daHttpActionResult(result.Result, result);
if (userviewmodel.Files != null && userviewmodel.Files.Count > 0)
{
userView.ProfileDocument = new UserDocument
{
DocumentName = userviewmodel.Files[0].Name,
Document = userviewmodel.Files[0].Value.Buffer,
UserID = UserId,
DocumentType = DocumentTypeEnum.ProfilePicture,
DocumentTypeOtherDescription = userviewmodel.Files[0].Value.MediaType,
};
}
return AdHttpActionResult(result.Result, result);
}
Thanks & Regards,
Cristina

composing form data with HttpClient

I want to send form data to my webserver from a Windows Phone 8 application. The data contains a file to upload and additional some strings (key=value).
The composing and sending of the file works fine. But how can I add now my strings to the send content?
string mServerUrl = #"http://www.myserver/reveiver.asp";
_ImageMemoryStream.Position = 0;
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(CreateFileContent(_ImageMemoryStream, "uploadedphoto.jpg", "image/jpeg"));
HttpClient mHttpClient = new HttpClient();
HttpResponseMessage mResponse = null;
mResponse = await mHttpClient.PostAsync(mServerUrl, content);
string responseBodyAsText = await mResponse.Content.ReadAsStringAsync();
if (mResponse.StatusCode == HttpStatusCode.OK)
{
txtError.Text = "OK:" + responseBodyAsText;
}
else
{
txtError.Text = "ERROR (" + mResponse.StatusCode + "):\n" + mResponse.ReasonPhrase;
}
Helper for composing the file:
private StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"file\"",
FileName = "\"" + fileName + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}
Adding my key/value pair in this way doesn´t fit:
content.Add("key", "value");
I want to add to my form-data some of These pairs ... Any help?
Got it on my own:
content.Add(new StringContent("value_string"), "\"key_string\"");
content.Add(CreateFileContent(mStream, mFilename, "image/jpeg"));
this works. Remeber my helper function CreateFileContent.
Try this:
List<KeyValuePair<string, string>> keyvaluePairs = new List<KeyValuePair<string,string>>();
KeyValuePair<string, string> keyvalue = new KeyValuePair<string, string>("key", "value");
keyvaluePairs.Add(keyvalue);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new FormUrlEncodedContent(keyvaluePairs));
Haven't tested this myself (with Multipart), but with FormUrlEncodedContent it works fine for me.

Categories