I'm trying to send some images + some meta data to a server by HTTP post from a windows store app but get stuck when trying to actually include the data in the post. It cannot be done the way you would accomplish this in a windows forms app or similar due to the changes to the store app API.
I get the error.
cannot convert source type byte[] to target type System.Net.Http.httpContent
now this is obviously because it's 2 different types that can't be implicitly casted, but it's basically what I'm looking to be able to do. How do I make get my byte array data into the httpContent type so I can include it in the following call
httpClient.PostAsync(Uri uri,HttpContent content);
here's my full upload method:
async private Task UploadPhotos(List<Photo> photoCollection, string recipient, string format)
{
PhotoDataGroupDTO photoGroupDTO = PhotoSessionMapper.Map(photoCollection);
try
{
var client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
client.DefaultRequestHeaders.Add("Upload", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
// POST action_begin
const string actionBeginUri = "http://localhost:51139/PhotoService.axd?action=Begin";
HttpResponseMessage response = await client.GetAsync(actionBeginUri);
response.EnsureSuccessStatusCode();
string responseBodyAsText = await response.Content.ReadAsStringAsync();
string id = responseBodyAsText;
////
// POST action_upload
Uri actionUploadUri = new Uri("http://localhost:51139/PhotoService.axd?action=Upload&brand={0}&id={1}&name={2}.jpg");
var metaData = new Dictionary<string, string>()
{
{"Id", id},
{"Brand", "M3rror"}, //TODO: Denne tekst skal komme fra en konfigurationsfil.
{"Format", format},
{"Recipient", recipient}
};
string stringData = "";
foreach (string key in metaData.Keys)
{
string value;
metaData.TryGetValue(key, out value);
stringData += key + "=" + value + ",";
}
UTF8Encoding encoding = new UTF8Encoding();
byte[] byteData = encoding.GetBytes(stringData);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, actionUploadUri);
// send meta data
// TODO get byte data in as content
HttpContent metaDataContent = byteData;
HttpResponseMessage actionUploadResponse = await client.PostAsync(actionUploadUri, metaDataContent);
actionUploadResponse.EnsureSuccessStatusCode();
responseBodyAsText = await actionUploadResponse.Content.ReadAsStringAsync();
// send photos
// TODO get byte data in as content
foreach (byte[] imageData in photoGroupDTO.PhotosData)
{
HttpContent imageContent = imageData;
actionUploadResponse = await client.PostAsync(actionUploadUri, imageContent);
actionUploadResponse.EnsureSuccessStatusCode();
responseBodyAsText = await actionUploadResponse.Content.ReadAsStringAsync();
}
////
// POST action_complete
const string actionCompleteUri = "http://localhost:51139/PhotoService.axd?action=Complete";
HttpResponseMessage actionCompleteResponse = await client.GetAsync(actionCompleteUri);
actionCompleteResponse.EnsureSuccessStatusCode();
responseBodyAsText = await actionCompleteResponse.Content.ReadAsStringAsync();
////
}
catch (HttpRequestException e)
{
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
It will be more straightforward to use System.Net.Http.ByteArrayContent. E.g:
// Converting byte[] into System.Net.Http.HttpContent.
byte[] data = new byte[] { 1, 2, 3, 4, 5};
ByteArrayContent byteContent = new ByteArrayContent(data);
HttpResponseMessage reponse = await client.PostAsync(uri, byteContent);
For text only with an specific text encoding use:
// Convert string into System.Net.Http.HttpContent using UTF-8 encoding.
StringContent stringContent = new StringContent(
"blah blah",
System.Text.Encoding.UTF8);
HttpResponseMessage reponse = await client.PostAsync(uri, stringContent);
Or as you mentioned above, for text and images using multipart/form-data:
// Send binary data and string data in a single request.
MultipartFormDataContent multipartContent = new MultipartFormDataContent();
multipartContent.Add(byteContent);
multipartContent.Add(stringContent);
HttpResponseMessage reponse = await client.PostAsync(uri, multipartContent);
You need to wrap the byte array in an HttpContent type.
If you are using System,Net.Http.HttpClient:
HttpContent metaDataContent = new ByteArrayContent(byteData);
If you are using the preferred Windows.Web.Http.HttpClient:
Stream stream = new MemoryStream(byteData);
HttpContent metaDataContent = new HttpStreamContent(stream.AsInputStream());
The concept you are looking for is called Serialization. Serialization means preparing your data (which could be heterogeneous and without a predefined strucutre) for storage or transmission. Then, when you need to use the data again, you do the opposite operation, deserialization, and get back the original data structure. The link above shows a few methods on how this could be done in C#.
Related
In the following code, I can send a POST request for the webserver and get a response:
private static readonly HttpClient client = new HttpClient();
public async static Task<int> User(string email, string password)
{
email = email.ToLower();
string theEmail = Cryptor.Encrypt(email);
string thePass = Cryptor.Encrypt(password);
try
{
var values = new Dictionary<string, string>
{
{ "email", theEmail },
{ "password", thePass }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://url...", content);
var responseString = await response.Content.ReadAsStringAsync();
Globals.USER = JsonConvert.DeserializeObject<UserObject>(responseString);
return 1;
}
catch (Exception)
{
return 3;
}
}
Is there a way to get a file sending a POST request and then save this file in a specific folder in the user's computer?
(What would be the PHP code to return the file after receiving the user's credentials and how would I get this file in the C# code?)
For example:
<?php
if($_SERVER['REQUEST_METHOD'] == "POST"){
$email = $_POST['email'];
$password = $_POST['password'];
// Validate user
// .
// .
// .
// Until here it's ok
// Now what would be the code to return the file?
// For example, a file from the following path: "user-folder/docs/image.png"
}else{
echo 'error';
die;
}
And in the WPF App, in C# usually I would read the response like this:
var response = await client.PostAsync("https://url...", content);
var responseString = await response.Content.ReadAsStringAsync();
But how would it be to get the file back?
Sending files is generally done by transferring the content as binary data. If you don't explicitly send text data, using HttpClient.ReadAsString is useless. Either read the response content as byte array or as stream.
Sending the file using the readfile() function:
$file = 'user-folder/docs/image.png';
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' .filesize($file));
readfile($file);
exit;
There are alternatives e.g., using cURL etc.
To request and save the file on your C# client you can handle the response content directly as Stream or byte array:
var response = await httpClient.PostAsync("https://url...", content);
var destinationFilePath = "image.png";
await using var destinationStream = File.Create(destinationFilePath);
// Handle the response directly as Stream
await using Stream sourceStream = await response.Content.ReadAsStreamAsync();
await sourceStream.CopyToAsync(destinationStream);
// Alternatively, create the Stream manually
// or write the byte array directly to the file
byte[] sourceData = await response.Content.ReadAsByteArrayAsync();
await destinationStream.WriteAsync(sourceData);
I have image in the form of byte[] data and code to pass byte data to get response from client. I need help in putting them together
I tried to use the code where I have my byte data but the async operations created a lot of confusion
"data" contains the byte[] data
private async void InitializeVideoFeedModule()
{
//Must in UI thread
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
//Raw data and decoded data listener
if (videoParser == null)
{
videoParser = new DJIVideoParser.Parser();
videoParser.Initialize( delegate (byte[] data)
{
return DJISDKManager.Instance.VideoFeeder.ParseAssitantDecodingInfo(0, data);
});
}
}
}
code to pass byte data and get response
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Prediction-Key", "XXXXX");
// Prediction URL - replace this example URL with valid Prediction URL.
string sequenceURL = "https://abc/dcr/xyz";
HttpResponseMessage response;
using (var content = new ByteArrayContent(data))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(sequenceURL, content);
var output = await response.Content.ReadAsStringAsync();
Console.WriteLine(output);
JObject json = JObject.Parse(output);
}
The delegate object and async operations are causing conflicts when I use them together.
I am trying to upload an image using Zendesk API v2, I am posting the file to /api/v2/uploads.json using RestSharp, and the file appears in the ticket once I create the ticket and add the attachment, the issue is that if I upload an image it won't open on the ticket, it is broken, if its a .txt file it has extra data there, this is my method:
var client = new RestSharp.RestClient(model.RequestUri);
client.Authenticator = new HttpBasicAuthenticator(string.Format("{0}/token", model.Username), model.Password);
var request = new RestRequest("/api/v2/uploads.json", Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "text/plain");
request.AlwaysMultipartFormData = true;
request.Parameters.Clear();
request.RequestFormat = RestSharp.DataFormat.Json;
//request.AddBody(createUpload);
byte[] bytes = System.IO.File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/Media/uploads/test.txt"));
request.AddFileBytes("Attachment", bytes, "test.txt", contentType: "text/plain");
request.AddParameter("filename", "test.txt");
IRestResponse response = client.Execute(request);
var content = JObject.Parse(response.Content);
return content["upload"]["token"].ToString();
This is the resulting txt file that's attached to the ticket:
-------------------------------28947758029299
Content-Disposition: form-data; name="filename"
test.txt
-------------------------------28947758029299
Content-Disposition: form-data; name="Attachment"; filename="test.txt"
Content-Type: application/octet-stream
testing txt
-------------------------------28947758029299--
The original file just has:
testing txt
Any ideas of what the error could be?
Thanks.
I solved the issue using an external library called ZendeskApi that's recommended in the Zendesk documentation: https://github.com/justeat/ZendeskApiClient
By using this library I was able to upload the attachments successfully and it works with any kind of file as well. It is also very easy to use, my method looks like this now:
IZendeskClient client = new ZendeskClient(
new Uri(model.RequestUri),
new ZendeskDefaultConfiguration(model.Username,
model.Password)
);
UploadRequest request = new UploadRequest() {
Item = model.Attachment.ConvertToZendeskFile()
};
IResponse<Upload> response = client.Upload.Post(request);
return response.Item.Token;
This is the ConvertToZendeskFile method:
private static ZendeskFile ConvertToZendeskFile(this HttpPostedFileBase rawFile)
{
return new ZendeskFile()
{
FileName = rawFile.FileName,
ContentType = rawFile.ContentType,
InputStream = rawFile.InputStream
};
}
The last step was creating a class that implemented IHttpPostedFile from the API:
public class ZendeskFile : IHttpPostedFile
{
public string ContentType { get; set; }
public string FileName { get; set; }
public Stream InputStream { get; set; }
}
This solved the issue for me, I hope it can help anyone facing the same problem.
I've managed to upload images and PDFs to Zendesk using a code snippet similar to this:
var client = new RestClient(apiUrl);
client.Authenticator = new HttpBasicAuthenticator(username + "/token", token);
client.AddDefaultHeader("Accept", "application/json");
string name = "name";
byte[] data; //Read all bytes of file
string filename = "filename.jpg";
var request = new RestRequest("/uploads.json", Method.POST);
request.AddFile(name, data, filename, "application/binary");
request.AddQueryParameter("filename", filename);
var response = client.Execute(request);
Need to add header ContentType=application/binary and provide file name in the URI ?filename=myfile.dat:
HttpClient client = [...];
var content = new ByteArrayContent(fileByteArray);
content.Headers.ContentType = new MediaTypeHeaderValue("application/binary");
HttpResponseMessage response = await client.PostAsync(url, content);
string responseString = await response.Content.ReadAsStringAsync();
From Zendesk documentation:
curl "https://{subdomain}.zendesk.com/api/v2/uploads.json?filename=myfile.dat&token={optional_token}" \
-v -u {email_address}:{password} \
-H "Content-Type: application/binary" \
--data-binary #file.dat -X POST
I had the same problem, Restsharp was sending the file as multipart, the only solution that worked for me was to send the file as parameter with content "application/binary".
public string UploadFile(ZendeskFile file)
{
try
{
var request = new RestRequest(FileUploadsPath, Method.POST);
request.AddQueryParameter("filename", file.Name);
request.AddParameter("application/binary", file.Data, ParameterType.RequestBody);
var response = Execute<UploadZendeskFileResponse>(request);
var result = JsonConvert.DeserializeObject<UploadZendeskFileResponse>(response.Content);
return result.upload.token;
}
catch (Exception ex)
{
throw ex;
}
}
I hope this helps someone else.
In my case, I did something like this. Hope you won't waste 6 hours like me!
public async Task UploadImageToZendesk(IFormFile image)
{
byte[] fileByteArray;
var request = new HttpRequestMessage();
var client = new HttpClient();
await using (var fileStream = image.OpenReadStream())
await using (var memoryStream = new MemoryStream())
{
await fileStream.CopyToAsync(memoryStream);
fileByteArray = memoryStream.ToArray();
}
ByteArrayContent byteContent = new ByteArrayContent(fileByteArray);
request.Content = byteContent;
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse($"application/binary");
await client.SendAsync(request);
}
Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).
I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?
using (var client = new HttpClient())
{
// Build the conversion options
var options = new Dictionary<string, string>
{
{ "value", html },
{ "apikey", ConfigurationManager.AppSettings["pdf:key"] },
{ "MarginLeft", "10" },
{ "MarginRight", "10" }
};
// THIS LINE RAISES THE EXCEPTION
var content = new FormUrlEncodedContent(options);
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
I receive this rediculous error.
{System.UriFormatException: Invalid URI: The Uri string is too long.
at System.UriHelper.EscapeString
at System.Uri.EscapeDataString
at System.Net.Http.FormUrlEncodedContent.Encode
at System.Net.Http.FormUrlEncodedContent.GetContentByteArray
This reminds me of 640k ought to be enough... I mean really?
If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:
// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).
using (var client = new HttpClient())
{
// Build the conversion options
var options = new
{
value = html,
apikey = ConfigurationManager.AppSettings["pdf:key"],
MarginLeft = "10",
MarginRight = "10"
};
// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(options);
var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
Make sure to install newtonsoft json.
I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".
This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).
private string UploadFile(string filename, int CustomerID, byte[] ImageData) {
string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);
var baseAddress = new Uri("[PUT URL HERE]");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
try {
//ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size.
string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
//THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");
//UPLOAD
string url = string.Format("/ajax/customer_image_upload.php");
response = client.PostAsync(url, content).Result;
return response.Content.ToString();
}
catch (Exception ex) {
return ex.ToString();
}
}
}
#Mick Byrne :
Thanks - your solution worked like a charme!
Here is my complete code:
public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
{
var client = new HttpClient();
// Create the HttpContent for the form to be posted.
var requestContent = new[] {
new KeyValuePair<string, string>("dateiname", Dateiname),
new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
new KeyValuePair<string, string>("ebene", "ebene"),
new KeyValuePair<string, string>("raumnummer", "raumnummer"),
new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
new KeyValuePair<string, string>("VRPinX", VRPinX),
new KeyValuePair<string, string>("VRPinY", VRPinY),
new KeyValuePair<string, string>("VRPinZ", VRPinZ),
};
String url = "http://yourhomepage/path/upload.php";
var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
}
I have a Windows Phone application in C#. I am trying send a image (byte[]) and a session token (string) to my django server, but not how to do it.
I 've looked at other post but it does not work what they do , or classes that use do not exist.
The header of my function is:
public static async Task<bool> sendImagePerfil(string token, byte[] imagen)
{
using (var client = new HttpClient())
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("token", token));
values.Add(new KeyValuePair<string, string>("image", Convert.ToString(imagen)));
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("MyURL.domain/function", content);
var responseString = await response.Content.ReadAsStringAsync();
}
}
EDITED: My problem now is my server don't get the image. The django code is:
if request.method == 'POST':
form = RestrictedFileField(request.POST, request.FILES)
token = models.UsuarioHasToken.objects.get(token=parameters['token'])
user = token.user
print (request.FILES['image'])
user.image = request.FILES['image']
I can't modify the django code because this code it's working with Android app
Using this response ,
How to upload file to server with HTTP POST multipart/form-data
Try with this...
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(new StringContent(token), "token");
var imageForm = new ByteArrayContent(imagen, 0, imagen.Count());
imagenForm.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
form.Add(imagenForm, "image", "nameholder.jpg");
HttpResponseMessage response = await httpClient.PostAsync("your_url_here", form);
response.EnsureSuccessStatusCode();
httpClient.Dispose();
string result = response.Content.ReadAsStringAsync().Result;