Does anyone know how to use the HttpClient in .Net 4.5 with multipart/form-data upload?
I couldn't find any examples on the internet.
my result looks like this:
public static async Task<string> Upload(byte[] image)
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(image)), "bilddatei", "upload.jpg");
using (
var message =
await client.PostAsync("http://www.directupload.net/index.php?mode=upload", content))
{
var input = await message.Content.ReadAsStringAsync();
return !string.IsNullOrWhiteSpace(input) ? Regex.Match(input, #"http://\w*\.directupload\.net/images/\d*/\w*\.[a-z]{3}").Value : null;
}
}
}
}
It works more or less like this (example using an image/jpg file):
async public Task<HttpResponseMessage> UploadImage(string url, byte[] ImageData)
{
var requestContent = new MultipartFormDataContent();
// here you can specify boundary if you need---^
var imageContent = new ByteArrayContent(ImageData);
imageContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("image/jpeg");
requestContent.Add(imageContent, "image", "image.jpg");
return await client.PostAsync(url, requestContent);
}
(You can requestContent.Add() whatever you want, take a look at the HttpContent descendant to see available types to pass in)
When completed, you'll find the response content inside HttpResponseMessage.Content that you can consume with HttpContent.ReadAs*Async.
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:
private static void Upload()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service");
using (var content = new MultipartFormDataContent())
{
var path = #"C:\B2BAssetRoot\files\596086\596086.1.mp4";
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();
}
}
}
Try this its working for me.
private static async Task<object> Upload(string actionUrl)
{
Image newImage = Image.FromFile(#"Absolute Path of image");
ImageConverter _imageConverter = new ImageConverter();
byte[] paramFileStream= (byte[])_imageConverter.ConvertTo(newImage, typeof(byte[]));
var formContent = new MultipartFormDataContent
{
// Send form text values here
{new StringContent("value1"),"key1"},
{new StringContent("value2"),"key2" },
// Send Image Here
{new StreamContent(new MemoryStream(paramFileStream)),"imagekey","filename.jpg"}
};
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(actionUrl.ToString(), formContent);
string stringContent = await response.Content.ReadAsStringAsync();
return response;
}
Here is another example on how to use HttpClient to upload a multipart/form-data.
It uploads a file to a REST API and includes the file itself (e.g. a JPG) and additional API parameters. The file is directly uploaded from local disk via FileStream.
See here for the full example including additional API specific logic.
public static async Task UploadFileAsync(string token, string path, string channels)
{
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
// add API method parameters
multiForm.Add(new StringContent(token), "token");
multiForm.Add(new StringContent(channels), "channels");
// add file and directly upload it
FileStream fs = File.OpenRead(path);
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(path));
// send request to API
var url = "https://slack.com/api/files.upload";
var response = await client.PostAsync(url, multiForm);
}
Here's a complete sample that worked for me. The boundary value in the request is added automatically by .NET.
var url = "http://localhost/api/v1/yourendpointhere";
var filePath = #"C:\path\to\image.jpg";
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
FileStream fs = File.OpenRead(filePath);
var streamContent = new StreamContent(fs);
var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(imageContent, "image", Path.GetFileName(filePath));
var response = httpClient.PostAsync(url, form).Result;
Example with preloader Dotnet 3.0 Core
ProgressMessageHandler processMessageHander = new ProgressMessageHandler();
processMessageHander.HttpSendProgress += (s, e) =>
{
if (e.ProgressPercentage > 0)
{
ProgressPercentage = e.ProgressPercentage;
TotalBytes = e.TotalBytes;
progressAction?.Invoke(progressFile);
}
};
using (var client = HttpClientFactory.Create(processMessageHander))
{
var uri = new Uri(transfer.BackEndUrl);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
using (MultipartFormDataContent multiForm = new MultipartFormDataContent())
{
multiForm.Add(new StringContent(FileId), "FileId");
multiForm.Add(new StringContent(FileName), "FileName");
string hash = "";
using (MD5 md5Hash = MD5.Create())
{
var sb = new StringBuilder();
foreach (var data in md5Hash.ComputeHash(File.ReadAllBytes(FullName)))
{
sb.Append(data.ToString("x2"));
}
hash = result.ToString();
}
multiForm.Add(new StringContent(hash), "Hash");
using (FileStream fs = File.OpenRead(FullName))
{
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(FullName));
var response = await client.PostAsync(uri, multiForm);
progressFile.Message = response.ToString();
if (response.IsSuccessStatusCode) {
progressAction?.Invoke(progressFile);
} else {
progressErrorAction?.Invoke(progressFile);
}
response.EnsureSuccessStatusCode();
}
}
}
I'm adding a code snippet which shows on how to post a file to an API which has been exposed over DELETE http verb. This is not a common case to upload a file with DELETE http verb but it is allowed. I've assumed Windows NTLM authentication for authorizing the call.
The problem that one might face is that all the overloads of HttpClient.DeleteAsync method have no parameters for HttpContent the way we get it in PostAsync method
var requestUri = new Uri("http://UrlOfTheApi");
using (var streamToPost = new MemoryStream("C:\temp.txt"))
using (var fileStreamContent = new StreamContent(streamToPost))
using (var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true })
using (var httpClient = new HttpClient(httpClientHandler, true))
using (var requestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri))
using (var formDataContent = new MultipartFormDataContent())
{
formDataContent.Add(fileStreamContent, "myFile", "temp.txt");
requestMessage.Content = formDataContent;
var response = httpClient.SendAsync(requestMessage).GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
{
// File upload was successfull
}
else
{
var erroResult = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
throw new Exception("Error on the server : " + erroResult);
}
}
You need below namespaces at the top of your C# file:
using System;
using System.Net;
using System.IO;
using System.Net.Http;
P.S. You are seeing a number of using blocks(IDisposable pattern) in the above code snippet which doesn't look very clean. Unfortunately, the syntax of using construct doesn't support initializing multiple variables in single statement.
X509Certificate clientKey1 = null;
clientKey1 = new X509Certificate(AppSetting["certificatePath"],
AppSetting["pswd"]);
string url = "https://EndPointAddress";
FileStream fs = File.OpenRead(FilePath);
var streamContent = new StreamContent(fs);
var FileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
FileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("ContentType");
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(clientKey1);
handler.ServerCertificateValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) =>
{
return true;
};
using (var client = new HttpClient(handler))
{
// Post it
HttpResponseMessage httpResponseMessage = client.PostAsync(url, FileContent).Result;
if (!httpResponseMessage.IsSuccessStatusCode)
{
string ss = httpResponseMessage.StatusCode.ToString();
}
}
public async Task<object> PassImageWithText(IFormFile files)
{
byte[] data;
string result = "";
ByteArrayContent bytes;
MultipartFormDataContent multiForm = new MultipartFormDataContent();
try
{
using (var client = new HttpClient())
{
using (var br = new BinaryReader(files.OpenReadStream()))
{
data = br.ReadBytes((int)files.OpenReadStream().Length);
}
bytes = new ByteArrayContent(data);
multiForm.Add(bytes, "files", files.FileName);
multiForm.Add(new StringContent("value1"), "key1");
multiForm.Add(new StringContent("value2"), "key2");
var res = await client.PostAsync(_MEDIA_ADD_IMG_URL, multiForm);
}
}
catch (Exception e)
{
throw new Exception(e.ToString());
}
return result;
}
I'm trying to use chat.postMesage with Slack's API but can't send an attachment as part of the message.
I thought I can use image_url as part of the attachment object in order to show an image as part of my message.
I'm not getting any error in the response but either don't see any attachment.
The message is being posted but no attachments at all.
Here's what I'm trying to do
public async Task<string> PostMessage()
{
var response = string.Empty;
var slacAttributes = new stackAttributes
{
channel = "testapp",
text = $" {DateTime.Now} > {Environment.NewLine} Good Morning all!!!{Environment.NewLine} new line",
attachments = new slackAttachments { fallback = "exception", text = "image text",title="kuku", image_url = "https://i.imgur.com/jO9N3eJ.jpg" }
};
try
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xoxp-927360717313-937536168112-927367533025-c1065234477a3de10257bc69f523f789");
var atttrJson = slacAttributes;
var json = new JavaScriptSerializer().Serialize(atttrJson);
var buffer = System.Text.Encoding.UTF8.GetBytes(json);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage result = await client.PostAsync("https://slack.com/api/chat.postMessage", byteContent);
if(result.IsSuccessStatusCode)
{
var content = await result.Content?.ReadAsByteArrayAsync();
response = Encoding.UTF8.GetString(content, 0, content.Length);
}
}
}
catch(Exception e)
{
throw new Exception($"An error occured while Posting to slack.{e}");
}
return response;
}
The attachments property has to be an array of attachment objects. From your code it looks like you are only providing a single attachment object, but not an array.
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);
I am trying to call the Web api method for saving the File Data.When I debug Webapi method I found that ContentLength is not coming as correct, because of this when i am retrieving the file it is showing error as corrupted file.
My Class method is :-
using (var formData = new MultipartFormDataContent())
{
HttpContent stringContent = new StringContent(file);
formData.Add(stringContent, "file", file);
formData.Add(new StringContent(JsonConvert.SerializeObject(file.Length)), "ContentLength ");
HttpResponseMessage responseFile = client.PostAsync("Report/SaveFile?docId=" + docId, formData).Result;
}
My Web api method is :-
[HttpPost]
public HttpResponseMessage SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var httpRequest = HttpContext.Current.Request;
bool IsSuccess = true;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
HttpPostedFile postedFile = httpRequest.Files[file];
// Initialize the stream.
Stream myStream = postedFile.InputStream;
myStream.Position = 0;
myStream.Seek(0, SeekOrigin.Begin);
var _item = CorrectedReportLibrary.Services.ReportService.SaveFile(myStream,docId);
response = Request.CreateResponse<bool>((IsSuccess)
? HttpStatusCode.OK
: HttpStatusCode.NoContent,
IsSuccess);
}
}
}
catch (Exception ex)
{
Theranos.Common.Library.Util.LogManager.AddLog(ex, "Error in CorrectedReportAPI.Controllers.SaveDocument()", null);
return Request.CreateResponse<ReportDocumentResult>(HttpStatusCode.InternalServerError, null);
}
return response;
}
How can I set the ContentLength from C# class method?
It looks a bit strange that you use ContentLength as the second parameter on the StringContent class. It is suppose to be which encoding you want to use, for example
new StringContent(content, Encoding.UTF8). I don't think it is the content length that is the issue here.
StringContent class
I guess since it is a file you want to upload, you already have the file read as a stream, so I usually do something like this:
Client:
private async Task UploadFile(MemoryStream file)
{
var client = new HttpClient();
var content = new MultipartFormDataContent();
content.Add(new StreamContent(file));
var result = await client.PostAsync("Report/SaveFile?docId=" + docId, content);
}
Edit. Since it's a multipartform it's easier to let the framework handle the details. Try something like this:
Server:
[HttpPost]
public async Task<HttpResponseMessage> SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var filedata = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach(var file in filedata.Contents)
{
var fileStream = await file.ReadAsStreamAsync();
}
response = Request.CreateResponse<bool>(HttpStatusCode.OK, true);
}
catch (Exception ex)
{
response = Request.CreateResponse<bool>(HttpStatusCode.InternalServerError, false);
}
return response;
}
At Last I found the solution no need to change the web api service,
issue was from client where I was directly passing the file data, Now the modified
working code is like this:-
using (var formData = new MultipartFormDataContent())
{
var bytes = File.ReadAllBytes(file);
formData.Add(new StreamContent(new MemoryStream(bytes)), "file", file);
HttpResponseMessage responseFile = client.PostAsync("ReportInfo/SaveFile?docId=" + docId, formData).Result;
}
Can any one explain how can i make POST request to a URL on web with different type of data, in my case i have an image and two string type values to send to a server in PHP.
here what i already have done
var stream = await file.OpenStreamForReadAsync();
var streamcontent = new StreamContent(stream);
streamcontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "photo",
FileName = file.Name
};
streamcontent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
MultipartFormDataContent multipart = new MultipartFormDataContent();
multipart.Add(streamcontent);
try
{
descContent = mytextbox.Text;
var stringcontent = new StringContent(descContent);
stringcontent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("description", descContent));
multipart.Add(stringcontent);
HttpResponseMessage res = await client.PostAsync(new Uri("http://localhost/web/test/index.php"), multipart);
res.EnsureSuccessStatusCode();
mytextbox.Text = await res.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
mytextbox.Text = ex.Message;
}
this code will send the image file but not the description(string), i have searched over the internet but I could not find appropriate answer.
here is the PHP code
if (isset($_FILES['photo']))
{
echo $_FILES["photo"]["name"] . "<br>";
}
else
{
echo "Image: Error<br>";
}
if (isset($_POST['description']))
{
echo $_POST['description'];
}
else
{
echo "Text: Error";
}
any response will be highly appreciated.
thank you
I have search a lot and finally got the way out. here is the code
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://www.yourdomain.com");
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent content = new StringContent("your string type data you want to post");
form.Add(content, "name");
var stream = await file.OpenStreamForReadAsync();
content = new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "image",
FileName = file.Name
};
form.Add(content);
var response = await client.PostAsync("index.php", form);
mytextblock.Text = response.Content.ReadAsStringAsync();
I wrote it on my blog here is the code. :-)
HappyCoding
Upload files with HTTPWebrequest (multipart/form-data)
http://www.paraesthesia.com/archive/2009/12/16/posting-multipartform-data-using-.net-webrequest.aspx/