C# RestSharp PUT method and send raw bytes (protobuf) - c#

How to send a byte array using HTTP PUT method?
Method AddFile of the class RestRequest sends extra headers.
Method AddParameter takes an Object type.
How I do it:
byte[] data;
using (var ms = new MemoryStream())
{
Serializer.Serialize(ms, query);
data = ms.ToArray();
ms.Close();
}
var client = new RestClient(ServerPath);
var request = new RestRequest(RequestPath, Method.PUT);
request.AddFile("stream", x => new MemoryStream(data), string.Empty);
client.ExecuteAsync(request, responce => Debug.WriteLine(responce.Content));
But on server side I see extra headers
-------------------------------28947758029299
Content-Disposition: form-data; name="stream"; filename=""
Content-Type: application/octet-stream
[RAW DATA HERE]
-------------------------------28947758029299--
Extra headers make query unreadable. What I do wrong?

Thanks to Marc Gravell.
Solution:
var client = new HttpClient();
var httpContent = new ByteArrayContent(data);
client.PutAsync(Path, httpContent);

I struggle on this for sometimes and finally found the solution
the magic is to give as request body without parameter name
// file to send
IFormFile file
byte[] buffer;
using (var ms = new MemoryStream())
using (var stream = file.OpenReadStream())
{
stream.CopyTo(ms);
buffer = ms.ToArray();
}
var uploadDoc = new RestRequest("ressource", Method.POST);
uploadDoc.RequestFormat = DataFormat.None;
uploadDoc.AddParameter("", buffer, ParameterType.RequestBody);
var response = new RestClient("baseUrl").Execute(uploadDoc);
hope it can help others

Related

PDF corrupted when uploading a document with .NET HttpClient

I am trying to upload a document to this AdobeSign API endpoint
While I have found a way to do it succesfully with the RestSharp RestClient with my below code:
var client = new RestClient("https://api.na2.echosign.com/api/rest/v6/transientDocuments");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer MyIntegratorKey");
var bytes = Convert.FromBase64String(base64Document);
var contents = new MemoryStream(bytes);
request.Files.Add(new FileParameter
{
Name = "File",
Writer = (s) =>
{
var stream = contents;
stream.CopyTo(s);
stream.Dispose();
},
FileName = "Test2.pdf",
ContentType = null,
ContentLength = bytes.Length
});
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
I am having issues when I try to use the .NET HttpClient. My below code successfully upload the document (HTTP 201 returned by Adobe) but the document is completely messed up when the signers open it.
Doesn't the .NET HttpClient support file uploads ? is there something wrong with my stream ?
Thank you in advance
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse("Bearer IntegratorKey");
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(new MemoryStream(Convert.FromBase64String(document.EmbeddedContent))), "File", "Test2.pdf");
using (
var message =
await client.PostAsync("https://api.na2.echosign.com/api/rest/v6/transientDocuments", content))
{
var input = await message.Content.ReadAsStringAsync();
Console.WriteLine(input);
}
}
}

Send an form-data post request with .Net framework HttpClient class containing a file

I need to recreate this request I made in Postman with C#, I found that the HttpClient class solves most of my problems, but this time I couldn't solve it on my own.
I embbeded an image with an example of the very post request.
POST REQUEST IN POSTMAN
There are three text paramethers and one file I need to send, with a content-type of form-data, the file needs to be a .json.
I tried constructing the POST request in many ways; this is my last version:
string endpoint = $"{Endpoint}/captcha";
string token_paramsJSON = JsonConvert.SerializeObject(v3Request.token_params);
Hashtable ParametrosPOSTCaptcha = GetV3POSTParams(v3Request);
UnicodeEncoding uniEncoding = new UnicodeEncoding();
using (Stream ms = new MemoryStream()) {
var sw = new StreamWriter(ms, uniEncoding);
sw.Write(token_paramsJSON);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
form.Add(new StringContent(v3Request.username), "username");
form.Add(new StringContent(v3Request.password), "password");
form.Add(new StringContent(v3Request.type.ToString()), "type");
form.Add(new StreamContent(ms));
var response = await _httpClient.PostAsync(endpoint, form);
string ResponseTest = await GetResponseText(response);
}
}
With this code, I successfully establish a connection with the endpoint, send the username and password.
But the response differs from the one I get with Postman using the same paramethers:
Postman: x=0&xx=1892036372&xxx=&xxxxx=1
The actual response I get is this:
HttpClient: {"error": "not-logged-in"}
Thanks in advance!
Finally, I could solve it using the following implementation:
string endpoint = $"{Endpoint}/endpointName";
string token_paramsJSON = JsonConvert.SerializeObject(v3Request.token_params, Formatting.Indented);
Dictionary<string,string> PostParams = GetPOSTParams(v3Request);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, endpoint);
UnicodeEncoding uniEncoding = new UnicodeEncoding();
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
foreach(var field in PostParams)
{
StringContent content = new StringContent(field.Value);
content.Headers.ContentType = null;
form.Add(content, field.Key);
}
var JsonFile = new StringContent(token_paramsJSON);
JsonFile.Headers.ContentType = new MediaTypeHeaderValue("application/json");
JsonFile.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"token_params\"",
FileName = "\"token.json\""
};
form.Add(JsonFile);
request.Content = form;
var response = await _httpClient.SendAsync(request, CancellationToken.None);
return await GetCaptchaFromResponse(response);
}

Error while trying to upload files to Zendesk Api 2 in c#

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

How to return a IHttpActionResult with Http status code 200 and pass in a memory stream in the http response

In my APIController.cs Get() method, how can I return a IHttpActionResult with HTTP status code 200 and pass in a memory stream in the HTTP response?
I tried doing this:
var sr = new StreamReader(myMemoryStream);
string myStr = sr.ReadToEnd();
return Ok(myStr);
But it converts my memory stream to string and pass that to Ok(). But I don't want to my memory stream to stream before sending in http respone.
And I don't see any method in the OkResult object which allows me to set the response stream.
How can I set the http response body?
public HttpResponseMessage GetFile()
{
byte[] byteArray;
using (MemoryStream memoryStream = new MemoryStream())
{
// Do you processign here
byteArray = memoryStream.ToArray();
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new ByteArrayContent(byteArray);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
//suppose its .xlsx file
response.Content.Headers.ContentDisposition.FileName = "Sample.xlsx";
return response;
}
if you are returning IHttpActionResult, then return
return ResponseMessage(GetFile());
Please let me know if you want client side code also
Try this code
public IHttpActionResult GetStream()
{
MemoryStream myMemoryStream = new MemoryStream();
var sr = new System.IO.StreamReader(myMemoryStream);
string myStr = sr.ReadToEnd();
return Ok(myStr);
}

Using Telegram API via HTTP

I'm trying to use the Telegram API via http (documentation on their site says this is possible) to authorize, following these instructions:
https://core.telegram.org/mtproto/auth_key#dh-exchange-initiation
https://core.telegram.org/mtproto/description#unencrypted-message
However, I cannot get any response from the server except a 404 page. Here is the code I'm using:
async Task<String> SendAuthorizeRequestTEST()
{
HttpClient client = new HttpClient();
String message = "req_pq#60469778 3761821:int128 = ResPQ";
HttpContent content = new ByteArrayContent(Packetify(message));
HttpResponseMessage msg = await client.PostAsync(new Uri("http://149.154.167.40:443"), content);
byte[] bytes = await msg.Content.ReadAsByteArrayAsync();
return Encoding.UTF8.GetString(bytes);
}
public byte[] Packetify(String message)
{
var memoryStream = new MemoryStream();
var binaryWriter = new BinaryWriter(memoryStream);
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
binaryWriter.Write(0); //auth_key_id
binaryWriter.Write(1234567); //message_id
binaryWriter.Write(messageBytes.Length); //message_data_length
binaryWriter.Write(messageBytes); //message_data
byte[] packet = memoryStream.ToArray();
memoryStream.Dispose();
binaryWriter.Dispose();
return packet;
}
What am I doing wrong?
You could study what webogram does. It uses the HTTP protocol to speak to telegram.
Further more here are some steps you can use to move along quickly
https://stackoverflow.com/a/34929980/44080
cheers.

Categories

Resources