How do I upload document by converting HttpClient request to RestSharp request? - c#

After i logged in to API i used, I am trying to upload a document with using RestSharp.
I was able to do this using Postman. Screenshot is given below:
Postman code generator generates this code block for me:
var client = new RestClient("http://80.211.238.187/AcumaticaERP/entity/Default/17.200.001/StockItem/POSTMAN123/files/sample.pdf");
client.Timeout = -1;
var request = new RestRequest(Method.PUT);
request.AddHeader("Content-Type", "application/pdf");
request.AddParameter("application/pdf", "<file contents here>", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
but idk how to edit the <file contents here> part from given code block above.
I was also able to achieve it using the HttpClient suggested in the respective API's documentation guide:
using (StreamReader sr = new StreamReader(#"C:\Users\fcomak\Downloads\sample.pdf"))
{
_httpClient.PutAsync("http://80.211.238.187/AcumaticaERP/entity/Default/17.200.001/StockItem/POSTMAN123/files/sample.pdf", new StreamContent(sr.BaseStream))
.Result
.EnsureSuccessStatusCode();
}
But i need to convert HttpClient request to RestSharp request. I tried to achieve this using RestSharp, but failed. Even if I could send the file, its content was not browse correctly. Here is the code block i tried:
using (StreamReader sr = new StreamReader(#"C:\Users\fcomak\Downloads\sample.pdf"))
{
restClient.Execute(new RestRequest("http://80.211.238.187/AcumaticaERP/entity/Default/17.200.001/StockItem/POSTMAN123/files/sample.pdf", Method.PUT)
.AddHeader("Content-Type", "application/pdf")
.AddParameter("application/pdf", new StreamContent(sr.BaseStream), ParameterType.RequestBody));
}
I can sending or getting json contents by using this api with this restClient by the way. And of course i logged in already. The reason for my failure is about my restClient.
I would be grateful for any help.

I just solved the problem.
using (WebClient wc = new WebClient())
{
byte[] value = wc.DownloadData("http://www.africau.edu/images/default/sample.pdf");
restClient.Execute(new RestRequest("http://80.211.238.187/AcumaticaERP/entity/Default/17.200.001/StockItem/POSTMAN123/files/sample.pdf", Method.PUT)
.AddHeader("Content-Type", "application/pdf")
.AddParameter("application/pdf", value, ParameterType.RequestBody)
);
}
As you see, i used WebClient.DownloadData() instead of StreamReader.BaseStream()
Or, you can convert you local data to byte array with File.ReadAllBytes()
string entitySource = #"C:\Users\fcomak\Downloads\sample2.pdf";
byte[] value = File.ReadAllBytes(entitySource);
restClient.Execute(new RestRequest(entityBasePath + entityName + "/" + inventoryID + "/files/" + fileName, Method.PUT)
.AddHeader("Content-Type", "application/pdf")
.AddParameter("application/pdf", value, ParameterType.RequestBody)
);
FYI

Related

Upload raw byte data with dotnet core HttpClient

I am updating some old C# code to use HttpClient instead of WebClient. As part of this, I need to upload a byte array of a file to an api.
With WebClient, this worked perfectly fine
byte[] data = GetMyData();
using (var client = new WebClient())
{
//set url, headers etc
var r = client.UploadData(url, "PUT", data);
}
With HttpClient, I've tried various methods, such as
byte[] data = GetMyData();
using (var client = new HttpClient())
{
//set url, headers etc
var r = await client.PutAsync(url, new ByteArrayContent(data));
}
I've also tried different ways of using Multipart data that I found Googling around, but the server does not accept anything I've tried. I don't have a lot of documentation on the server API, I only know that the WebClient way has worked well for many years. Is there a way to recreate the WebClient.UploadData behavior with HttpClient?
Thanks to the commenters for putting me on the right track. The Content-Type headers were not being set correctly for the HttpClient way, by putting it on the actual content. code below.
byte[] data = GetMyData();
using (var client = new HttpClient())
{
//set url, headers etc
var content = new ByteArrayContent(data);
content.Headers.ContentType = new MediaTypeWithQualityHeaderValue(contentType);
var r = await client.PutAsync(url, content);
}

Mapping JSON from Yahoo! Finance API to C# objects [duplicate]

This question already has answers here:
Deserialize JSON data with C#
(4 answers)
Closed 1 year ago.
I am a student working on a project. I am trying to use the Yahoo! Finance API as a source for my data https://www.yahoofinanceapi.com . I can use HttpWebRequests to call the API and get the "OK" code, see the code below on how I did it:
string BaseURL = "https://yfapi.net/v6/finance/quote?symbols=AAPL";
string addSymbol = "%2C";
string URL = BaseURL;
foreach (string stock in stocks)
{
URL += addSymbol + stock;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Headers.Add("X-API-KEY", "[My API key]");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
response.ContentType gives back "application/json".
response.StatusCode gives back "OK".
Since the response is a JSON I tried to parse it into a string using .ToString() but this obviously doesn't work. When I print it, it just says "System.Net.HttpWebResponse" instead of the showing the actual data in the JSON.
After that I tried to deserialize it using newtonsoft
Results result = JsonConvert.DeserializeObject<Results>(request.GetResponse().ToString());
where Results is a class I made where there is a list of stocks, Stock is also a class I made with some variables in it with the same names of variables in the JSON response.
I got a JSON response from PostMan when I tested the API, opened the response to see what kind of data it contained.
When I ran my code I got the following error message:
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: S. Path '', line 0, position 0.'
This was as far as I got, I tested a few other methods trying to get this working but this one worked the "best".
My biggest issue at the moment is mapping the response into a c# object.
Anything that can help me understand is appreciated :D
You're trying to serialise the HttpWebResponse object into Results, which means deserialisation won't work.
The data is still wrapped & won't be in the format of the Results object.
The GetResponseStream() method can be used to get the contents of the HTTP response as a stream, which can then be deserialised directly, in this case, using Json.NET.
Replace this section:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
With this:
var serializer = new JsonSerializer();
using (var response = (HttpWebResponse)request.GetResponse())
{
var encoding = Encoding.GetEncoding(response.CharacterSet);
using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream, encoding);
using (var jsonTextReader = new JsonTextReader(reader))
{
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
Results result = serializer.Deserialize<Results>(jsonTextReader);
}
}
Alternatively, a much better solution if you're using .NET 4.5 <= would be to use HttpClient like below:
private static readonly HttpClient httpClient = new HttpClient();
...
string BaseURL = "https://yfapi.net/v6/finance/quote?symbols=AAPL";
string addSymbol = "%2C";
string URL = BaseURL;
foreach(string stock in stocks) {
URL += addSymbol + stock;
}
client.DefaultRequestHeaders.Add("X-API-KEY", "[My API key]");
var data = await httpClient.GetStringAsync(address);
Results result = JsonConvert.DeserializeObject<Results>(data);

Problem calling the prediction endpoint uploading an image using rest sharp for the Microsoft custom vision API cognitive service

I am trying to upload an image to the Microsoft custom vision API prediction endpoint using Restsharp, I am trying to use the AddFile method but I am getting a BadRequest as the result, here is the code I am using
public IRestResponse<PredictionResponse> Predict(string imageFileName)
{
var file = new FileInfo(imageFileName);
var serviceUrl = ConfigurationManager.AppSettings["api.custom-vision.prediction.url.file"];
var serviceKey = ConfigurationManager.AppSettings["api.custom-vision.key"];
var client = new RestClient(serviceUrl);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("Prediction-Key", serviceKey);
request.AddFile(file.Name, file.FullName);
var response = client.Execute<PredictionResponse>(request);
return response;
}
When I execute the method I am getting the following response back from the service
{
"code": "BadRequestImageFormat",
"message": "Bad Request Image Format, Uri: 1062fe0480714281abe2daf17beb3ac5"
}
After looking for ways in the restsharp documentation to properly upload a file, I came to the solution that it needs to be passed as parameter with an array of bytes with the parameter type of ParameterType.RequestBody
Here is the example of the method that actually works
public IRestResponse<PredictionResponse> Predict(string imageFileName)
{
var file = new FileInfo(imageFileName);
var serviceUrl = ConfigurationManager.AppSettings["api.custom-vision.prediction.url.file"];
var serviceKey = ConfigurationManager.AppSettings["api.custom-vision.key"];
var client = new RestClient(serviceUrl);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("Prediction-Key", serviceKey);
request.AddParameter("content", File.ReadAllBytes(file.FullName), ParameterType.RequestBody);
var response = client.Execute<PredictionResponse>(request);
return response;
}

Trouble making POST request from c# [.NET]

We have a created an API for the application which takes the image via POST request process it and sends the result in JSON format.
We tried calling API from different sources like python, postman app, c#. We can successfully call end point using python and postman app but with c# getting error
c# code [Not working]
byte[] img_data = System.IO.File.ReadAllBytes(#"file_path");
string url_ep = "http://ip:port/get";
Dictionary<string, byte[]> fl_image = new Dictionary<string, byte[]>();
fl_image.Add("image", img_data);
string data = JsonConvert.SerializeObject(fl_image);
var dataToSend = Encoding.UTF8.GetBytes(data);
var request = HttpWebRequest.Create(url_ep);
request.ContentType = "application/json";
request.ContentLength = dataToSend.Length;
request.Method = "POST";
request.GetRequestStream().Write(dataToSend, 0, dataToSend.Length);
var response = request.GetResponse();
System.IO.Stream dataStream = response.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
Console.WriteLine(responseFromServer);
python code [working]
import requests
url = 'http://ip:port/get'
fl_image = {'image': open('file_path', 'rb')}
res = requests.post(url, files=fl_image)
print(res.json())
API Endpoint
from flask import Flask, request
import numpy as np
import cv2 as cv
#app.route('/get', methods = ['POST'])
def get_image():
if request.method == 'POST':
file = request.files['image']
# Read file
f = file.read()
# convert string of image data to uint8
f1 = np.fromstring(f, np.uint8)
# decode image
f2 = cv.imdecode(f1,cv.IMREAD_COLOR)
There are several issues with the way you are posting data from C#. The most relevant one is that you are trying to post a file as a JSON object, with file contents as string.
This cannot work: your python server is clearly expecting multipart/form-data as content-type.
I also strongly recommend you to use HttpClient and not the old HttpWebRequest class to send HTTP Requests.
var filePath = #"file_path";
var url = "http://ip:port/get";
using (var client = new HttpClient())
using (var content = new MultipartFormDataContent())
using (var fileStream = File.OpenRead(filePath))
{
var imageContent = new StreamContent(fileStream);
// NOTE: the line below is not required, but useful when you know the media type
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(imageContent, "image", Path.GetFileName(filePath));
var response = await client.PostAsync(url, content);
var stringResponse = await response.Content.ReadAsStringAsync();
// do what you need with the response
}
Other minor issues:
Do not read the entire file in memory (using File.ReadAllBytes), but open a stream for reading instead.
Use async/await when possible, do not block on async code (do not use .Result, .Wait() or .GetAwaiter().GetResult() on Task or Task<T>)
Always call Dispose() on IDisposable objects when you have finished using them (wrapping them inside a using block)
You need to dispose the connections
reader.Close();
dataStream.Close();
response.Close();
Hope this helps
Or try using HttpClient for .net within the using block

Softlayer Object Storage ETag MD5 Checksum Calculation

I'm trying to figure out how to calculate the correct checksum when passing data to the Softlayer Object Storage.
I know the ETag is the issue because if I remove it form the request it works, however I'd prefer to use it to verify the uploads are not corrupt.
This is my method:
public bool SaveFile(byte[] file, eFetchStorageContainers container, string internalFileName, string fileName = "", bool overPublicNetwork = false)
{
Authenticate(overPublicNetwork);
client = new RestClient(storage_url);
var resourcePath = string.Format("/{0}/{1}", container, internalFileName);
var req = new RestRequest(resourcePath, RestSharp.Method.PUT);
req.AddHeader("X-Auth-Token", auth_token);
req.AddFile(internalFileName, file, fileName);
var md5Checksum = BitConverter.ToString(MD5.Create().ComputeHash(file)).Replace("-", string.Empty).ToLower();
req.AddHeader("ETag", md5Checksum);
var resp = client.Execute(req);
return false;
}
Here is how the ETag is defined:
I believe the problem lies in the fact that i'm getting the checksum for the file and not the request body.
I want to verify that I should be getting the checksum of the Request Body and NOT the file alone.
If the above is true I'm not even sure how to get the checksum for the body - would love some guidance...
Well I did not use C#, but it works using curl fine for me. I get the checksum for the file and it is working fine.
just in case here some examples about this https://community.runabove.com/kb/en/object-storage/how-to-check-file-consistency-using-etag-and-md5.html
Make sure that your request is similar to examples of the link above.
This is the curl I used:
curl -X PUT -T "C:\Users\ncabero\Downloads\picture.jpg" -H "X-Auth-Token: AUTH_XXXXXXX" -H "Etag: a43bf68dd35599a7873c12128f71b1f4" https://dal05.objectstorage.softlayer.net/v1/AUTH_d684780d-aafe-4772-bcbb-0f07d5f6edf3/rcvtest/picture.jpg
I actually figured this out, I was using RestSharp however its impossible to get the request body.
I moved over to HttpClient and was able to access the request body to create a checksum.
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("X-Auth-Token", auth_token);
var bytes = new ByteArrayContent(file);
var formData = new MultipartFormDataContent();
formData.Add(bytes, internalFileName, internalFileName);
// this creates a checksum to send over for verification of non corrupted transfers
// this is also prevents us from using RestSharp due to its inability to create a checksum of the request body prior to sending
var md5Checksum = BitConverter.ToString(MD5.Create().ComputeHash(formData.ReadAsByteArrayAsync().Result)).Replace("-", string.Empty).ToLower();
httpClient.DefaultRequestHeaders.Add("ETag", md5Checksum);
var url = string.Format("{0}/{1}{2}/{3}", storage_url, containerName, folderId, internalFileName);
var resp = httpClient.PutAsync(url, formData).Result;
httpClient.Dispose();

Categories

Resources