Httpclient asp.net core curl equivalent - c#

I have an issue with ASP.Net HttpClient POST request.
In fact I want to index documents in Solr using SolrCell. I have used curl like this:
curl 'http://localhost:8983/solr/my_collection/update/extract?literal.id=doc1&commit=true' -F "myfile=#example/exampledocs/solr-word.pdf"
Unfortunately I was only able to send the file as Multi-part file upload (with HttpClient), this way I need to determine the mime type of the file, which I did but I still got errors for DOCX and PPTX files.
Here is my code:
var fileBytes = File.ReadAllBytes(path);
requestContent.Add(new ByteArrayContent(fileBytes), "file");
requestContent.Headers.Remove("Content-Type");
requestContent.Headers.Add("Content-Type", contentType);
var response = await client.PostAsync(defaultSolrUri, requestContent);
return response.Content;
Please help.

I found the solution! No need to pass MultiPartFormData, all you need to do is to pass the file as ByteArrayContent in PostAsyn:
string path = "path/to/file";
var fileBytes = File.ReadAllBytes(path);
var response = await client.PostAsync(defaultSolrExtractUri, new ByteArrayContent(fileBytes));
return response.Content;

Related

Uploading a file like form-data in postman

I have found some answers here that give examples but none seems to work for me..
this is how my postman looks:
In the code I download the picture from a URL, save it as jpeg inside a folder and then I try to upload that image with a POST request, here is how it looks:
var fileName = image.PhotoId + ".jpeg";
await Task.WhenAll(client.DownloadFileTaskAsync(new Uri(image.ImageUrl), #"wwwroot\images\"+fileName));
var files = Directory.GetFiles(#"wwwroot\images\", "*.jpeg");
var filePath = Path.Combine(#"wwwroot\images\", fileName);
using var stream = File.OpenRead(filePath);
var file_content = new ByteArrayContent(new StreamContent(stream).ReadAsByteArrayAsync().Result);
var formData = new MultipartFormDataContent();
formData.Add(file_content, "file", fileName);
var res = await clientAsync.PostAsync(url, formData);
problem is the response that I get in the code is an error..:
{"error_code":6,"error_message":"Sorry, please try a different picture"}
this type of response is the same one I get when trying to upload a pdf instead of a jpeg on postman so I guess the file is getting corrupted in the code somewhere.
would love to get any ideas to where the problem is!

Send a 'Stream' over a PutAsync request

I'm trying my hand at .NET Core but I'm stuck trying to convert multipart/form-data to an application/octet-stream to send via a PUT request. Anybody have any expertise I could borrow?
[HttpPost("fooBar"), ActionName("FooBar")]
public async Task<IActionResult> PostFooBar() {
HttpResponseMessage putResponse = await _httpClient.PutAsync(url, HttpContext.Request.Body);
}
Update: I think I might have two issues here:
My input format is multipart/form-data so I need to split out the file from the form data.
My output format must be application-octet stream but PutAsync expects HttpContent.
I had been trying to do something similar and having issues. I needed to PUT large files (>1.5GB) to a bucket on Amazon S3 using a pre-signed URL. The implementation on Amazon for .NET would fail for large files.
Here was my solution:
static HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromMinutes(60);
static async Task<bool> UploadLargeObjectAsync(string presignedUrl, string file)
{
Console.WriteLine("Uploading " + file + " to bucket...");
try
{
StreamContent strm = new StreamContent(new FileStream(file, FileMode.Open, FileAccess.Read));
strm.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
HttpResponseMessage putRespMsg = await client.PutAsync(presignedUrl, strm);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
return true;
}
Turns out Request has a Form property that contains a Files property that has an OpenReadStream() function on it to convert it into a stream. How exactly I was supposed to know that, I'm not sure.
Either way, here's the solution:
StreamContent stream = new StreamContent(HttpContext.Request.Form.Files[0].OpenReadStream());
HttpResponseMessage putResponse = await _httpClient.PutAsync(url, stream);

How to Post a web request and receive a file from web API response?

I have an Infopath Form Template on Sharepoint, I want to add a button there so when the user clicks on it, it will POST an string to the following Web API. The following web API is tested and returns an excel file as shown:
I want to Post the FileName of the excel file using post request and it is important for me the request method to be POST type. and then the user will download a file with the specified 'FileName'.
Actually i want to use post method because at the next stage i will send the content of the excel file too.
Important Note: I only can use .Net FrameWork 3.5 because this is the only framework supported in InfoPath Form Templates.
[HttpPost]
public HttpResponseMessage Post([FromBody]string FileName)
{
string reqBook = "c:\somefile.xlsx";
//converting Excel(xlsx) file into bytes array
var dataBytes = File.ReadAllBytes(reqBook);
//adding bytes to memory stream
var dataStream = new MemoryStream(dataBytes);
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = FileName;
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
return httpResponseMessage;
}
When you perform the HttpPost on the client side, you will want to read the HttpResponseStream to get the byte data of the response stream.
Once you have the response stream data, you can then deserialize it to the type of object in C# you want, or you could alternatively just write it to the disk as
File.WriteAllBytes("someexcel.xlsx",data);
An easy way to do it would be with the HttpClient class.
HttpClient client = new HttpClient();
var response = client.PostAsync("", null).Result;
var content = response.Content.ReadAsByteArrayAsync().Result;
File.WriteAllBytes("excel.xlsx", content);
Just fill in the PostAsync bit with the Url and the content you wish to post.
I am using .Result to keep everything synchronous - but you can use 'await' if you prefer.
If you are working with HttpWebRequests - then the process becomes more complicated, as you need to manage the streams yourself.
The HttpClient will manage and handle it all for you - so I recommend it, unless there is something special it needs to do that it currently does not.
Due to your .Net 3.5 requirement:
private static HttpWebResponse MakeRequest(string url, string postArgument)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/form-data;";
Stream stream = request.GetRequestStream();
string result = string.Format("arg1={0}", postArgument);
byte[] value = Encoding.UTF8.GetBytes(result);
stream.Write(value, 0, value.Length);
stream.Close();
return (HttpWebResponse)request.GetResponse();
}
You can then do:
var response = MakeRequest("http://mywebsite.com/ProcessExcel", "accounts.xlsx");
And then do
Stream objStream = response .GetResponseStream();
BinaryReader breader = new BinaryReader(objStream);
byte[] data= breader.ReadBytes((int)webresponse.ContentLength);
File.WriteAllBytes("excel.xlsx",data);

"No file uploaded or URL provided" when calling ocr.space API

I'm trying to call this API from my C# app:
https://ocr.space/OCRAPI
When I call it from curl, it just works fine:
curl -k --form "file=#filename.jpg" --form "apikey=helloworld" --form "language=eng" https://api.ocr.space/Parse/Image
I implemented it this way:
[TestMethod]
public async Task Test_Curl_Call()
{
var client = new HttpClient();
String cur_dir = Directory.GetCurrentDirectory();
// Create the HttpContent for the form to be posted.
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>( "file", "#filename.jpg"), //I also tried "filename.jpg"
new KeyValuePair<string, string>( "apikey", "helloworld" ),
new KeyValuePair<string, string>( "language", "eng")});
// Get the response.
HttpResponseMessage response = await client.PostAsync(
"https://api.ocr.space/Parse/Image",
requestContent);
// Get the response content.
HttpContent responseContent = response.Content;
// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Write the output.
String result = await reader.ReadToEndAsync();
Console.WriteLine(result);
}
}
I get this answer :
{
"ParsedResults":null,
"OCRExitCode":99,
"IsErroredOnProcessing":true,
"ErrorMessage":"No file uploaded or URL provided",
"ErrorDetails":"",
"ProcessingTimeInMilliseconds":"0"
}
Any clue?
What's the # character for in "file=#filename.jpg"?
I put my filename.jpg file in the project and test project bin/debug directory and run my test project in debug mode.
So I don't think the error points to the file not being where expected.
I'd rather suspect a syntax error in my code.
The error message is telling you what's wrong:
No file uploaded or URL provided
You sent a filename to the service in your code, but that's not the same thing as giving curl a filename. curl is smart enough to read the file and upload the contents with your request, but in your C# code, you'll have to do that yourself. The steps will be:
Read the file bytes from disk.
Create a multipart request with two parts: the API key ("helloworld"), and the file bytes.
POST this request to the API.
Fortunately, it's pretty easy. This question demonstrates the syntax to set up a multipart request.
This code worked for me:
public async Task<string> TestOcrAsync(string filePath)
{
// Read the file bytes
var fileBytes = File.ReadAllBytes(filePath);
var fileName = Path.GetFileName(filePath);
// Set up the multipart request
var requestContent = new MultipartFormDataContent();
// Add the demo API key ("helloworld")
requestContent.Add(new StringContent("helloworld"), "apikey");
// Add the file content
var imageContent = new ByteArrayContent(fileBytes);
imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
requestContent.Add(imageContent, "file", fileName);
// POST to the API
var client = new HttpClient();
var response = await client.PostAsync("https://api.ocr.space/parse/image", requestContent);
return await response.Content.ReadAsStringAsync();
}

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