HttpClient PostAsync List<string> instead of file.csv - c#

I am attempting to post content to a vendor. The data uploads when I save my data to a .csv then reference the file. What I would prefer to do is skip saving the file to disk and just upload the data. I can't seem to figure out how to serialize the data correctly.
Here is the data:
csv.Add(string.Join(",", "sara1234", "Ancient World Studies-1201A1-01"));
csv.Add(string.Join(",", "jazzy4567", "Ancient World Studies-1201A1-01"));
Here is the upload:
protected async Task<bool> RunAsync(string baseAddress, IEnumerable<string> file, string passkey)
{
byte[] csvBytes = File.ReadAllBytes("C:\\Projects\\AutomationServiceFiles\\DataMig_Test\\Drop\\Hapara\\HaparaStudent.csv");
var csvContent = new ByteArrayContent(csvBytes);
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
content.Add(new StringContent(passkey), "passkey");
content.Add(csvContent, "uploadFile", "student.csv");
var response = await client.PostAsync(baseAddress, content);
response.EnsureSuccessStatusCode();
string returnedContent = await response.Content.ReadAsStringAsync();
}
}
return true;
}
I have tried what's shown below (instead of the file from disk). I get a 200 success message back, but data does not load. Specifically, the first method returns a message that the students were not found (this is good because I know the data was evaluated), the second returns no message at all.
string jsonFile = JsonConvert.SerializeObject(file);
HttpContent contentPost = new StringContent(jsonFile, Encoding.UTF8, "application/json");
content.Add(contentPost, "uploadFile", "student.csv");
Any suggestions?

You could just build the CSV string and pass it to a new instance of StringContent instead of using ByteArrayContent.

Related

.NET Core 3 MVC download a file from HTTP and re-deliver to client using minimum memory

I have a .NET Core 3 MVC app that needs to read a file from one location over HTTP and then re-deliver it back out to the response. Some of these files will be ~200MB in size.
What I have works, but it reads the whole file into memory before sending the File result out to the client. Is there a way to make it essentially a passthrough where the read stream flows into the response stream so that very little memory is required on the server?
This is what I have now but I do not think will perform well with large files:
if (requestedFile != null)
{
using (var client = new System.Net.Http.HttpClient())
{
using (var result = await client.GetAsync(requestedFile.DownloadUrl))
{
if (result.IsSuccessStatusCode)
{
var bytes = await result.Content.ReadAsByteArrayAsync();
return File(bytes, "application/zip", "largefile.zip");
}
}
}
}
I have also tried this which results in a runtime error of "Cannot access a closed Stream":
using (var client = new System.Net.Http.HttpClient())
{
using (var httpResponseMessage = await client.GetAsync(requestedFile.DownloadUrl))
{
return File(await httpResponseMessage.Content.ReadAsStreamAsync(), "application/zip", "largefile.zip");
}
}
Edit:
Solution after some trial and error was remocing all using statements and letting the FileStreamResult close the stream on its own. So I ended up with:
var client = new HttpClient();
var result = await client.GetAsync(requestedFile.DownloadUrl);
var stream = await result.Content.ReadAsStreamAsync();
return new FileStreamResult(stream, "application/zip")
{
FileDownloadName = "largefile.zip"
};
One of the overloads for File is a Stream. Just get that URL as a Stream or read the response body as a stream and immediately return that in the overload:
var client = new System.Net.Http.HttpClient();
var result = await client.GetAsync(requestedFile.DownloadUrl);
var stream = await result.Content.ReadAsStreamAsync();
return File(stream,"application/pdf", "Invoice.pdf");
Note: this will fail if you wrap the Stream in a using block as the FileResult already closes the Stream.
For Export Excel
var client = new System.Net.Http.HttpClient();
var comp = client.GetAsync($"RewardEmployee/ExportExcelCalculate?rewardConfigId={id}").Result;
`var stream = await result.Content.ReadAsStreamAsync();
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"ExportExcelCalculateRewardEmployee.xlsx");

How can I create headers for a text file and upload it with httpClient?

My text file is saved on my hard disk and I want to upload it in Visual Studio to this file management service: https://learn.microsoft.com/en-us/gaming/playfab/features/data/content-delivery-network/quickstart#fetching-assets
Before uploading, I want to create the file headers, because I want to add a version number of the file to the headers. For example, I want to add "1" to the headers, if it is the first version. How can I do that?
After that, I want to upload the text file. But I don't know how to upload the file with httpClient. How can I upload the file?
I have tried it with this code, but it's not working and I don't know what I'm doing wrong. What is wrong?
private async Task UpoadNewContent()
{
var result = await PlayFabAdminAPI.GetContentUploadUrlAsync(new GetContentUploadUrlRequest()
{
Key = "Levelfiles/Level2.txt",
ContentType = "binary/octet-stream"
});
if (result.Error != null)
{
Console.WriteLine("Error.");
}
else
{
Uri webService = new Uri(result.Result.URL + "Levelfiles/" + "Level2.txt");
await UploadFileAsync(webService, "/Users/myname/TESTFOLDER/Level2.txt");
}
}
async Task UploadFileAsync(Uri uri, string filename)
{
using (var stream = File.OpenRead(filename))
{
var client = new HttpClient();
var response = await client.PostAsync(uri, new StreamContent(stream));
response.EnsureSuccessStatusCode();
}
}
I get this response:

WebApi Route fails if streamcontentis not empty

I'm trying to send an object using Web-APi 2 and protobuf-net. I keep getting a 404 error so I assume something goes wrong with the routing?
When I comment out the serialize line
ProtoBuf.Serializer.Serialize(memstream, package);
(so the memory stream stays empty) the routing works and RecievePackage is called. And the package parameter is empty. (the package object itsself is not NULL but all it's properties are.)
Whenever the memory stream is not empty I get a 404 error. What am I doing wrong here?
Receive code:
[Route("Receive")]
[HttpPost]
public async Task<IHttpActionResult> RecievePackage(PackageModel package)
{
id = await SavePackage(package);
return Created("", id);
}
Send code:
private async Task SyncUpAsync(string apiUrl, PackageModel package)
{
using (HttpClient client = new HttpClient())
using (var memstream = new MemoryStream())
{
var uri = new Uri(new Uri(ApiUrl), apiUrl);
ProtoBuf.Serializer.Serialize(memstream, package);
memstream.Position = 0;
var content = new StreamContent(memstream);
content.Headers.Add("SyncApiToken", ApiKey);
content.Headers.Add("Content-Type", "application/x-protobuf");
var response = await client.PostAsync(uri, content);
}
}

How to consume a webApi from asp.net Web API to store result in json file

How to consume RestApi using c# and to store the content of responses in json file? i.e When I run the program, it should call API and automatically it should store the json content in json file.
How can it be possible using Asp.Net?
You should use HTTP POST
using System.Net.Https; // Add this library
using (var client = new HttpClient())
{
var values = "DataToSend";
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://sit.com/sample.aspx", content);
var responseString = await response.Content.ReadAsStringAsync(); //JSON
}
You can call any rest api using httpclient(Microsoft.AspNet.WebApi.Client)
Following method returns a json string async which you can save later
static async Taskstring> GetContentAsync(string path)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(address);
}
to get json content synchronously
using (var client = new HttpClient())
{
var response = client.GetAsync("http://example.com").Result;
if (response.IsSuccessStatusCode)
{
string responseString = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseString);//you can save the responseString here
}
}
or use open source library like RestSharp
var client = new RestClient("http://example.com");
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
More examples can be found https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client or using restsharp

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

Categories

Resources