Consider this small code below:
var client = new HttpClient();
var multiForm = new MultipartFormDataContent();
var str = new StreamContent(File.OpenRead("movie.mp4"));
multiForm.Add(str, "to_upload", "1.mp4");
var response = await client.PostAsync("https://example.com/upload", multiForm);
As you can see I'm using StreamContent and MultipartFormDataContent to upload a file. My question is it is possible to somehow get the upload progress from HttpClient? Or any other way to get upload progress?
You can make use of ProgressableStreamContent from here
or this answer
and a simple usage can be
var progress = new ProgressableStreamContent (
requestContent,
4096,
(sent,total) => {
Console.WriteLine ("Uploading {0}/{1}", sent, total);
});
Related
I am a beginner to GET and POST. I apologize if the question sounds stupid. But I need your help in guiding me to do it the correct way.
I have to periodically do GET from server A indefinitely until user terminate using Ctrl + C
To check at interval I use the timer below
Timer timer = new Timer(RunTask, null, 3000, 3000);
Where RunTask is the callback method consists of GET method to retrieve data below
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(urlA);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<RootObject>(responseBody);
}
Then register the data to server B through POST method
using (HttpClient client = new HttpClient())
{
var json = JsonConvert.SerializeObject(rootIssue);
var output = new StringContent(json, Encoding.UTF8, "application/json");
var result = await client.PostAsync(urlB, output);
string response = result.Content.ReadAsStringAsync().Result;
}
Once registered, server B will return with updated info which I have to POST back to server A
using (HttpClient client = new HttpClient())
{
var json = JsonConvert.SerializeObject(rootIssue);
var output = new StringContent(json, Encoding.UTF8, "application/json");
var result = await client.PostAsync(urlA, output);
string response = result.Content.ReadAsStringAsync().Result;
}
My question here is, what is the best approach for me to do all these queries in my console app? Should I separate each GET and POST to these
GetFromA()
PostToB()
PostToA()
I am concerned if I do it this way, is it possible that PostToB() will POST with incomplete response from GetFromA()?
Or should I combine GET and POST from A to B in one method to something like
GetFromAPostToB()
I hope that someone can point me in the correct direction.
Thanks.
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");
In my WP8.1 Silverlight app, I want to download a file and save it to an isolated storage. The downloading is OK, but how I can save it ?
For the downloading, I use this :
var HttpClientDownloadFile = new Windows.Web.Http.HttpClient();
Windows.Web.Http.HttpRequestMessage request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Get, new Uri(downloadUrl));
request.Headers.Add("Range", "bytes=0-");
// Hook up progress handler.
Progress<HttpProgress> progressCallback = new Progress<HttpProgress>(OnSendRequestProgress);
var tokenSource = new CancellationTokenSource();
Windows.Web.Http.HttpResponseMessage response = await HttpClientDownloadFile.SendRequestAsync(request).AsTask(tokenSource.Token, progressCallback);
If I run the debug, in response.content I have my download. Now, I want to save it to the isolated storage. How can I do that ? Should I use an stream ?
Thanks
Convert your response to stream and write it to file
using (var fileStream = await this.storageFile.OpenFileAsync(fileName, FileMode.OpenOrCreate))
{
await stream.CopyToAsync(fileStream);
}
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.
I'm using the following code to download an image from a url
HttpClient client = new HttpClient();
var stream = await client.GetStreamAsync(new Uri("<your url>"));
var file = await KnownFolders.PictureLibrary.CreateFileAsync("myfile.png");
using (var targetStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (stream)
await stream.CopyToAsync(targetStream.AsStreamForWrite());
}
several users have reported that it doesn't always download the entire image. That they sometimes get partial images and the rest is just garbage.
Is there any reason for this?
Thanks!
I would suggest trying the WebClient class with the DownloadData or DownloadDataAsync method.
File.WriteAllBytes("myfile.png",
new WebClient().DownloadData("<your url>"));
edit If the stream is giving you trouble you could use the byte array response instead. Your "using" statement with async code inside may be causing it to dispose early, perhaps?
var httpClient = new HttpClient();
var data = await httpClient.GetByteArrayAsync(new Uri("<Your URI>"));
var file = await KnownFolders.PictureLibrary.CreateFileAsync("myfile.png");
var targetStream = await file.OpenAsync(FileAccessMode.ReadWrite)
await targetStream.AsStreamForWrite().WriteAsync(data, 0, data.Length);
targetStream.FlushAsync().Wait();
targetStream.Close();
BackgroundDownloader is the easiest way to download a file.
using Windows.Storage;
public async Task DownloadPhoto(Uri uri)
{
var folder = ApplicationData.Current.LocalFolder;
var photoFile = await folder.CreateFileAsync("photo.jpg", CreationCollisionOption.ReplaceExisting);
var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
var dl = downloader.CreateDownload(uri, photoFile);
await dl.StartAsync();
}
If your using HttpClient then if your image is larger than 64K it will error out. You will have to set the httpClient.MaxResponseContentBufferSize to something larger.
See the MSDN Quick Start where they set the max-buffer-size to 256K.
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/JJ152726(v=win.10).aspx
Personally though, I use the BackgroundDownloader.