Download file with WebClient or HttpClient? - c#

I am trying to download file from a URL and I have to choose between WebClient and HttpClient. I have referenced this article and several other articles on the internet. Everywhere, it is suggested to go for HttpClient due to its great async support and other .Net 4.5 privileges. But I am still not totally convinced and need more inputs.
I am using below code to download file from internet:
WebClient:
WebClient client = new WebClient();
client.DownloadFile(downloadUrl, filePath);
HttpClient:
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(url))
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
}
}
From my perspective, I can see only one disadvantage in using WebClient, that would be the non async call, blocking the calling thread. But what if I am not worried about the blocking of thread or use client.DownloadFileAsync() to leverage the async support?
On the other hand, if I use HttpClient, ain't I loading every single byte of a file into memory and then writing it to a local file? If the file size is too large, won't memory overhead be expensive? Which could be avoided if we use WebClient, since it will directly write to local file and not consume system memory.
So, if performance is my utter priority, which approach should I use for download? I would like to be clarified if my above assumption is wrong, and I am open to alternate approach as well.

You can do it natively with .Net 4.5+. I tried doing it your way and then I just found a method in Intellisense that seemed to make sense.
https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.copytoasync?view=netframework-4.7.2
uri = new Uri(generatePdfsRetrieveUrl + pdfGuid + ".pdf");
HttpClient client = new HttpClient();
var response = await client.GetAsync(uri);
using (var fs = new FileStream(
HostingEnvironment.MapPath(string.Format("~/Downloads/{0}.pdf", pdfGuid)),
FileMode.CreateNew))
{
await response.Content.CopyToAsync(fs);
}

Here is my approach.
If you are calling a WebApi to get a file, then from a controller method you can use HttpClient GET request and return file stream using FileStreamResult return type.
public async Task<ActionResult> GetAttachment(int FileID)
{
UriBuilder uriBuilder = new UriBuilder();
uriBuilder.Scheme = "https";
uriBuilder.Host = "api.example.com";
var Path = "/files/download";
uriBuilder.Path = Path;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(uriBuilder.ToString());
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("authorization", access_token); //if any
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(uriBuilder.ToString());
if (response.IsSuccessStatusCode)
{
System.Net.Http.HttpContent content = response.Content;
var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream
return File(contentStream, content_type, filename);
}
else
{
throw new FileNotFoundException();
}
}
}

To use HttpClient on my existing code that used WebClient, I wrote a small extension method to use it on the same way I used DownloadFileTaskAsync on my code.
using (var client = new System.Net.Http.HttpClient()) // WebClient
{
var fileName = #"C:\temp\imgd.jpg";
var uri = new Uri("https://yourwebsite.com/assets/banners/Default.jpg");
await client.DownloadFileTaskAsync(uri, fileName);
}
To use it we can have this extension method:
public static class HttpClientUtils
{
public static async Task DownloadFileTaskAsync(this HttpClient client, Uri uri, string FileName)
{
using (var s = await client.GetStreamAsync(uri))
{
using (var fs = new FileStream(FileName, FileMode.CreateNew))
{
await s.CopyToAsync(fs);
}
}
}
}

For code being called repeatedly, you do not want to put HttpClient in a using block (it will leave hanging ports open)
For downloading a file with HttpClient, I found this extension method which seemed like a good and reliable solution to me:
public static class HttpContentExtensions
{
public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite)
{
string pathname = Path.GetFullPath(filename);
if (!overwrite && File.Exists(filename))
{
throw new InvalidOperationException(string.Format("File {0} already exists.", pathname));
}
FileStream fileStream = null;
try
{
fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None);
return content.CopyToAsync(fileStream).ContinueWith(
(copyTask) =>
{
fileStream.Close();
});
}
catch
{
if (fileStream != null)
{
fileStream.Close();
}
throw;
}
}
}

Here’s one way to use it to download a URL and save it to a file: (I am using windows 7, therefore no WindowsRT available to me, so I’m also using System.IO.)
public static class WebUtils
{
private static Lazy<IWebProxy> proxy = new Lazy<IWebProxy>(() => string.IsNullOrEmpty(Settings.Default.WebProxyAddress) ? null : new WebProxy { Address = new Uri(Settings.Default.WebProxyAddress), UseDefaultCredentials = true });
public static IWebProxy Proxy
{
get { return WebUtils.proxy.Value; }
}
public static Task DownloadAsync(string requestUri, string filename)
{
if (requestUri == null)
throw new ArgumentNullException(“requestUri”);
return DownloadAsync(new Uri(requestUri), filename);
}
public static async Task DownloadAsync(Uri requestUri, string filename)
{
if (filename == null)
throw new ArgumentNullException("filename");
if (Proxy != null)
WebRequest.DefaultWebProxy = Proxy;
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
using (Stream contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync(), stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.LargeBufferSize, true))
{
await contentStream.CopyToAsync(stream);
}
}
}
}
}
Note that code is saving the address of the proxy server I use (at work) in a setting, and using that if such setting is specified. Otherwise, it should tell you all you need to know regarding using the HttpClient beta to download and save a file.

If you want (or have) to do this synchronously, but using the nice HttpClient class, then there's this simple approach:
string requestString = #"https://example.com/path/file.pdf";
var GetTask = httpClient.GetAsync(requestString);
GetTask.Wait(WebCommsTimeout); // WebCommsTimeout is in milliseconds
if (!GetTask.Result.IsSuccessStatusCode)
{
// write an error
return;
}
using (var fs = new FileStream(#"c:\path\file.pdf", FileMode.CreateNew))
{
var ResponseTask = GetTask.Result.Content.CopyToAsync(fs);
ResponseTask.Wait(WebCommsTimeout);
}

My approach is very simple. Using FileStream you can store it in the local folder, or return it from API using FileStreamResult.
Example for store into local folder:
private async Task SaveDataIntoLocalFolder(string url,string fileName)
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var stream = await response.Content.ReadAsStreamAsync();
var fileInfo = new FileInfo(fileName);
using (var fileStream = fileInfo.OpenWrite())
{
await stream.CopyToAsync(fileStream);
}
}
else
{
throw new Exception("File not found");
}
}
}

This is a simple demo UWP application for downloading an image file.
Just paste the image URL link and press the download button. You can identify the file type and change the fileName to download the desired file.
MainPage.xaml
<Page
x:Class="HttpDownloader.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HttpDownloader"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<TextBox x:Name="uriInput"
Header="URI:" PlaceholderText="Please provide an uri"
Width="300"
HorizontalAlignment="Center"/>
<Button Content="Dowload"
HorizontalAlignment="Center"
Click="Button_Click"/>
</StackPanel>
</Grid>
</Page>
MainPage.xaml.xs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net.Http;
using System.Net;
using Windows.Storage.Streams;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Graphics.Imaging;
using System.Threading;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace HttpDownloader
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
HttpClient client = new HttpClient();
string imageUrl = uriInput.Text;
try
{
using (var cancellationTokenSource = new CancellationTokenSource(50000))
{
var uri = new Uri(WebUtility.HtmlDecode(imageUrl));
using (var response = await client.GetAsync(uri, cancellationTokenSource.Token))
{
response.EnsureSuccessStatusCode();
var mediaType = response.Content.Headers.ContentType.MediaType;
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");
if (mediaType.IndexOf("jpg", StringComparison.OrdinalIgnoreCase) >= 0
|| mediaType.IndexOf("jpeg", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".jpg";
}
else if (mediaType.IndexOf("png", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".png";
}
else if (mediaType.IndexOf("gif", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".gif";
}
else if (mediaType.IndexOf("bmp", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".bmp";
}
else
{
fileName += ".png";
}
// Get the app's local folder.
StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
// Create a new subfolder in the current folder.
// Replace the folder if already exists.
string desiredName = "Images";
StorageFolder newFolder = await localFolder.CreateFolderAsync(desiredName, CreationCollisionOption.ReplaceExisting);
StorageFile newFile = await newFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream streamStream = await response.Content.ReadAsStreamAsync())
{
using (Stream streamToWriteTo = File.Open(newFile.Path, FileMode.Create))
{
await streamStream.CopyToAsync(streamToWriteTo);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occur");
Console.WriteLine(ex.ToString());
}
}
}
}
You will find the image in this folder.
Users/[current user name]/AppData/Local/Packages/[Application package name]/LocalState/Images

HttpClient _client=new HttpClient();
byte[] buffer = null;
try
{
HttpResponseMessage task = await _client.GetAsync("https://**FILE_URL**");
Stream task2 = await task.Content.ReadAsStreamAsync();
using (MemoryStream ms = new MemoryStream())
{
await task2.CopyToAsync(ms);
buffer = ms.ToArray();
}
File.WriteAllBytes("C:/**PATH_TO_SAVE**", buffer);
}
catch
{
}

Related

How to make an HttpClient call from c# to get the result from the below code

The below is a webservice running, I can use swagger and get the result file from apicontroller but having trouble making the call from console app to get the results.
What would a HttpClient call look like to get the results using c#.
[HttpGet, Route("api/DownloadHl7/{securitykey}/{specimenid}")]
public IHttpActionResult GetFileForCustomer(string securitykey, string specimenid) {
if (securitykey != Constants.ApiToken)
return BadRequest();
var file = FileToByteArray(pathtohl7 + specimenid + ".HL7");
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
responseMsg.Content = new ByteArrayContent(file);
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/HL7");
response = ResponseMessage(responseMsg);
return response;
}
public byte[] FileToByteArray(string fileName) {
byte[] fileData = null;
using (FileStream fs = File.OpenRead(fileName)) {
using (BinaryReader binaryReader = new BinaryReader(fs)) {
fileData = binaryReader.ReadBytes((int)fs.Length);
}
}
return fileData;
}
Finally got it to work using the below, There was no need to change apicontroller code, worked as is.
This will download the file to the local directory indicated in the correct format.
using (HttpClient client = new HttpClient()) {
var response = await client.GetStreamAsync(downloadurlurl + "securitykey" + "/" + "741562");
using (var fs = new FileStream(string.Format(#"C:\Bill\{0}.HL7", "741562"),
FileMode.CreateNew)) {
await response.CopyToAsync(fs);
}
}

Stream URL to Android.Graphics.Bitmap using BitmapFactory.DecodeStreamAsync on GZIP file

I need to decode a url to a Bitmap. I am using the following code to attempt to decode a stream.
async Task <Android.Graphics.Bitmap> GetImageFromUrl(string url) {
using(var client = new HttpClient()) {
var response = await client.GetAsync(url);
if (response != null && response.StatusCode == HttpStatusCode.OK) {
using(var stream = await response.Content.ReadAsStreamAsync()) {
return await BitmapFactory.DecodeStreamAsync(stream);
}
}
return null;
}
}
The url being supplied is a blank black image: https://assets.radiowave.io/prod/StationAssets/1/image-md.jpg
Why does the BitmapFactory.DecodeStreamAsync always return null?
You are trying to pass a GZIP'd stream to DecodeStream and thus it fails to determine the type image you are passing in. Add a HttpClientHandler to your HttpClient with automatic decompression enabled.
FYI: If this method is being called multiple times, you should treat HttpClient as a singleton and only createi t once.
async Task<Android.Graphics.Bitmap> GetBitmapFromUrlAsync(string url)
{
var handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip
};
using (var client = new HttpClient(handler))
{
var response = await client.GetAsync(url);
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
return await BitmapFactory.DecodeStreamAsync(stream);
}
}
return null;
}
}
I usually prefer to use the available Java API's since there are tons of examples that do work so the code should look something like this:
public async Task<Bitmap> GetBitmapFromUrlAsync(String src)
{
try
{
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection)url.OpenConnection();
connection.DoInput = (true);
await connection.ConnectAsync();
Stream input = connection.InputStream;
Bitmap myBitmap = await BitmapFactory.DecodeStreamAsync(input);
return myBitmap;
}
catch (IOException e)
{
// Log exception
return null;
}
}
And you will need the following using statements:
using Java.Net;
using System;
using System.IO;
using System.Threading.Tasks;
using Android.Graphics;
Also since you are making an API call make sure you have the try-catch ready.

"no_file_data" error when trying to upload file to slack

when I try to upload any kidn of file through my SlackApp(via c# using HttpClient),
I allways get the following response:
{"ok":false,"error":"no_file_data"}
I checked my ByteArray (I stream the file to an array and then try to upload) and wrote my data back into a .txt and .jpg - I tried both types of data. When i write them back they are exact copies from the original, so I guess my streaming and writing to an ByteArrayworks fine. But something is off with my upload.
I'll show you my code:
The Client and the method to upload:
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net.Http.Headers;
namespace SlackApp
{
public class SlackClient
{
private readonly Uri _webhookUrl;
private readonly HttpClient _httpClient = new HttpClient {};
public SlackClient(Uri webhookUrl)
{
_webhookUrl = webhookUrl;
}
public async Task<HttpResponseMessage> UploadFile(byte[] file)
{
var requestContent = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(file);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
requestContent.Add(fileContent, "slack", "slack.txt");
var response = await _httpClient.PostAsync(_webhookUrl, requestContent);
return response;
}
}
}
the creation of the bytearray:
public class PostFile
{
String path = #"C:\Users\f.held\Desktop\Held-Docs\dagged.jpg";
public byte[] ReadImageFile()
{
FileInfo fileInfo = new FileInfo(path);
long imageFileLength = fileInfo.Length;
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
BinaryReader br = new BinaryReader(fs);
byte[] imageData = br.ReadBytes((int)imageFileLength);
return imageData;
}
}
the Main:
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace SlackApp
{
class TestArea
{
public static void Main(string[] args)
{
Task.WaitAll(IntegrateWithSlackAsync());
}
private static async Task IntegrateWithSlackAsync()
{
var webhookUrl = new Uri("https://slack.com/api/files.upload?token=xoxp-hereStandsMyToken&channel=MyChannel");
var slackClient = new SlackClient(webhookUrl);
PostMessage PM = new PostMessage();
PostFile PF = new PostFile();
var testFile = PF.ReadImageFile();
while (true)
{
var message = Console.ReadLine();
FormUrlEncodedContent payload = PM.Content(message, "");
var response = await slackClient.SendMessageAsync(payload);
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content); //I build these two lines in here so I got the response from the method, and this is where it says "no_file_data"
var isValid = response.IsSuccessStatusCode ? "valid" : "invalid";
Console.WriteLine($"Received {isValid} response.");
Console.WriteLine(response); //this puts out a "valid" response - oddly enough
}
}
}
}
Does anybody have an idea what is wrong here? Why isn't it taking the data?
You have two bugs in your code:
main(): The parameter to specify the channels is called
channels, not channel
UploadFile(): When you add your file content to the multipart you
need to include the correct API parameter for the file which is file,
not slack. And also want to include a reasonable filename (instead of slack.txt).
Additional comments
UploadFile(): Its wrong to set the content type to multipart/form-data. The
correct type for that content would be image/jpeg. However, the
correct type seams to be detected automatically, so just remove the
line.
main(): The Slack API will always return OK (http 200, unless there is a network problem), so you want to also look on the ok and error properties of the JSON response instead.
Here is an update version of your code. I changed your main() method to include a call to `UploadFile()?.
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace SlackApp
{
public class PostFile
{
string path = #"C:\Users\Stratios_down.jpg";
public byte[] ReadImageFile()
{
FileInfo fileInfo = new FileInfo(path);
long imageFileLength = fileInfo.Length;
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
BinaryReader br = new BinaryReader(fs);
byte[] imageData = br.ReadBytes((int)imageFileLength);
return imageData;
}
}
public class SlackClient
{
private readonly Uri _webhookUrl;
private readonly HttpClient _httpClient = new HttpClient { };
public SlackClient(Uri webhookUrl)
{
_webhookUrl = webhookUrl;
}
public async Task<HttpResponseMessage> UploadFile(byte[] file)
{
var requestContent = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(file);
requestContent.Add(fileContent, "file", "stratios.jpg");
var response = await _httpClient.PostAsync(_webhookUrl, requestContent);
return response;
}
}
class TestArea
{
public static void Main(string[] args)
{
Task.WaitAll(IntegrateWithSlackAsync());
}
private static async Task IntegrateWithSlackAsync()
{
var webhookUrl = new Uri(
"https://slack.com/api/files.upload?token=xoxp-MY-TOKEN&channels=test"
);
var slackClient = new SlackClient(webhookUrl);
PostFile PF = new PostFile();
var testFile = PF.ReadImageFile();
var response = await slackClient.UploadFile(testFile);
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
Console.ReadKey();
}
}
}
In addition I would have a couple of suggestions to improve your code.
Instead of including the additional API parameters in the URL, I
would send them in the POST request as recommended by the API
documentation.
Including the file as FileStream instead of loading it yourself into
a ByteArray is the better approach and recommended for larger files.
Not sure why you need an infinite loop in your main. Those are really
bad and should be avoided.
Please also take also a look at my new async example for uploading a file to Slack where I applied those two ideas.
I was running into the no_file_data error as well. I found out you the file needs to exist AND it needs actual content inside. Make sure to do a size check or content length check in addition to the file exists check before uploading

Get picture from HttpClient

I need help retrieving a picture from a web service. It's a GET request.
At the moment I am retrieving a response and I am able to convert it to a byte array, which is what I am going for, but the byte array crashes the app, so I don't think the content is set right.
I have tried to set the response content with:
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = filename };
Even though my guess is that it is set incorrectly, or it is up in the requestHeader it is set wrong.
Any ideas?
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseurl.uri);
client.DefaultRequestHeaders.Add("x-access-token", sessionToken);
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("image/jpeg")
);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "");
try
{
Task<HttpResponseMessage> getResponse = client.SendAsync(request);
HttpResponseMessage response = new HttpResponseMessage();
response = await getResponse;
//1. response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = filename };
//2. response.Content.Headers.ContentType =
//new MediaTypeHeaderValue("image/jpeg");//("application/octet-stream");
byte[] mybytearray = null;
if (response.IsSuccessStatusCode)
{
//3.
mybytearray = response.Content.ReadAsByteArrayAsync().Result;
}
var responseJsonString = await response.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine(responseJsonString);
System.Diagnostics.Debug.WriteLine("GetReportImage ReponseCode: " + response.StatusCode);
return mybytearray;//{byte[5893197]}
}
catch (Exception ex)
{
string message = ex.Message;
return null;
}
}
You can send the valid byte array of the image as part of the HttpContent
HttpContent contentPost = new
StringContent(JsonConvert.SerializeObject(YourByteArray), Encoding.UTF8,
"application/json");
After deserializing your result you can retrieve your byte array save the same as jpeg or any other format.
byte[] imageByteArray = byteArray;
using(Image image = Image.FromStream(new MemoryStream(imageByteArray)))
{
image.Save("NewImage.jpg", ImageFormat.Jpeg);
}
You can get picture as any other type of file if you do not need to validate the file
using var httpClient = new HttpClient();
var streamGot = await httpClient.GetStreamAsync("domain/image.png");
await using var fileStream = new FileStream("image.png", FileMode.Create, FileAccess.Write);
streamGot.CopyTo(fileStream);
This is a simple demo UWP application for downloading an image file.
Just paste the image URL link and press the download button to download the desired the image file.
MainPage.xaml
<Page
x:Class="HttpDownloader.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HttpDownloader"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<TextBox x:Name="uriInput"
Header="URI:" PlaceholderText="Please provide an uri"
Width="300"
HorizontalAlignment="Center"/>
<Button Content="Dowload"
HorizontalAlignment="Center"
Click="Button_Click"/>
</StackPanel>
</Grid>
</Page>
MainPage.xaml.xs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net.Http;
using System.Net;
using Windows.Storage.Streams;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Graphics.Imaging;
using System.Threading;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace HttpDownloader
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
HttpClient client = new HttpClient();
string imageUrl = uriInput.Text;
try
{
using (var cancellationTokenSource = new CancellationTokenSource(50000))
{
var uri = new Uri(WebUtility.HtmlDecode(imageUrl));
using (var response = await client.GetAsync(uri, cancellationTokenSource.Token))
{
response.EnsureSuccessStatusCode();
var mediaType = response.Content.Headers.ContentType.MediaType;
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");
if (mediaType.IndexOf("jpg", StringComparison.OrdinalIgnoreCase) >= 0
|| mediaType.IndexOf("jpeg", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".jpg";
}
else if (mediaType.IndexOf("png", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".png";
}
else if (mediaType.IndexOf("gif", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".gif";
}
else if (mediaType.IndexOf("bmp", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".bmp";
}
else
{
fileName += ".png";
}
// Get the app's local folder.
StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
// Create a new subfolder in the current folder.
// Replace the folder if already exists.
string desiredName = "Images";
StorageFolder newFolder = await localFolder.CreateFolderAsync(desiredName, CreationCollisionOption.ReplaceExisting);
StorageFile newFile = await newFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream streamStream = await response.Content.ReadAsStreamAsync())
{
using (Stream streamToWriteTo = File.Open(newFile.Path, FileMode.Create))
{
await streamStream.CopyToAsync(streamToWriteTo);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occur");
Console.WriteLine(ex.ToString());
}
}
}
}
You will find the image in this folder.
Users/[current user name]/AppData/Local/Packages/[Application package name]/LocalState/Images

How do I use the new HttpClient from Windows.Web.Http to download an image?

Using Windows.Web.Http.HttpClient how can I download an image? I would like use this HttpClient because it is available to use in portable class libraries.
This is what I eventually came up with. There is not much documentation around Windows.Web.Http.HttpClient and a lot of the examples online use old mechanisms like ReadAllBytesAsync which are not available with this HttpClient.
I should note that this question from MSDN helped me out a lot, so thanks to that person. As the comment over there states, this guy must be the only person in the world who knows about Windows.Web.Http!
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Windows.Storage.Streams;
using Windows.Web.Http;
public class ImageLoader
{
public async static Task<BitmapImage> LoadImage(Uri uri)
{
BitmapImage bitmapImage = new BitmapImage();
try
{
using (HttpClient client = new HttpClient())
{
using (var response = await client.GetAsync(uri))
{
response.EnsureSuccessStatusCode();
using (IInputStream inputStream = await response.Content.ReadAsInputStreamAsync())
{
bitmapImage.SetSource(inputStream.AsStreamForRead());
}
}
}
return bitmapImage;
}
catch (Exception ex)
{
Debug.WriteLine("Failed to load the image: {0}", ex.Message);
}
return null;
}
}
In .net core web api you can use the below code
[Route("getProductImage/v1")]
[HttpGet]
public async Task<IActionResult> getProductImage(GetProductImageQueryParam parammodel)
{
using (HttpClient client = new HttpClient())
{
MNimg_URL = MNimg_URL + parammodel.modelname;
HttpResponseMessage response = await client.GetAsync(MNimg_URL);
byte[] content = await response.Content.ReadAsByteArrayAsync();
//return "data:image/png;base64," + Convert.ToBase64String(content);
return File(content, "image/png", parammodel.modelname);
}
}
here GetProductImageQueryParam is a class with input parameters
public async void downLoadImage(string url)
{
using (var client = new HttpClient())
{
var response = client.GetAsync(url).Result;
BitmapImage bitmap = new BitmapImage();
if (response != null && response.StatusCode == HttpStatusCode.OK)
{
using (var stream = await response.Content.ReadAsStreamAsync())
{
using (var memStream = new MemoryStream())
{
await stream.CopyToAsync(memStream);
memStream.Position = 0;
bitmap.SetSource(memStream.AsRandomAccessStream());
}
}
HardcodedValues.profilePic = bitmap;
}
}
}
Most answers here are correct but if you need something simple:
HttpClient http = new HttpClient();
var res = await http.GetAsync(linktojpg);
byte[] bytes = await res.Content.ReadAsByteArrayAsync();
using (Image image = Image.FromStream(new MemoryStream(bytes)))
{
image.Save(path/name.jpg); // Or Png
}
Updated for 8.1 - 10.
public async static Task<BitmapImage> LoadImage(Uri uri)
{
BitmapImage bitmapImage = new BitmapImage();
try
{
using (Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient())
{
using (var response = await client.GetAsync(uri))
{
response.EnsureSuccessStatusCode();
using (MemoryStream inputStream = new MemoryStream())
{
await inputStream.CopyToAsync(inputStream);
bitmapImage.SetSource(inputStream.AsRandomAccessStream());
}
}
}
return bitmapImage;
}
catch (Exception ex)
{
Debug.WriteLine("Failed to load the image: {0}", ex.Message);
}
return null;
}
Made a demo UWP application for downloading an image file.
Just paste the image URL link and press the download button.
MainPage.xaml
<Page
x:Class="HttpDownloader.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HttpDownloader"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<TextBox x:Name="uriInput"
Header="URI:" PlaceholderText="Please provide an uri"
Width="300"
HorizontalAlignment="Center"/>
<Button Content="Dowload"
HorizontalAlignment="Center"
Click="Button_Click"/>
</StackPanel>
</Grid>
</Page>
MainPage.xaml.xs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net.Http;
using System.Net;
using Windows.Storage.Streams;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Graphics.Imaging;
using System.Threading;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace HttpDownloader
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
HttpClient client = new HttpClient();
string imageUrl = uriInput.Text;
try
{
using (var cancellationTokenSource = new CancellationTokenSource(50000))
{
var uri = new Uri(WebUtility.HtmlDecode(imageUrl));
using (var response = await client.GetAsync(uri, cancellationTokenSource.Token))
{
response.EnsureSuccessStatusCode();
var mediaType = response.Content.Headers.ContentType.MediaType;
string fileName = DateTime.Now.ToString("yyyyMMddhhmmss");
if (mediaType.IndexOf("jpg", StringComparison.OrdinalIgnoreCase) >= 0
|| mediaType.IndexOf("jpeg", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".jpg";
}
else if (mediaType.IndexOf("png", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".png";
}
else if (mediaType.IndexOf("gif", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".gif";
}
else if (mediaType.IndexOf("bmp", StringComparison.OrdinalIgnoreCase) >= 0)
{
fileName += ".bmp";
}
else
{
fileName += ".png";
}
// Get the app's local folder.
StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
// Create a new subfolder in the current folder.
// Replace the folder if already exists.
string desiredName = "Images";
StorageFolder newFolder = await localFolder.CreateFolderAsync(desiredName, CreationCollisionOption.ReplaceExisting);
StorageFile newFile = await newFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (Stream streamStream = await response.Content.ReadAsStreamAsync())
{
using (Stream streamToWriteTo = File.Open(newFile.Path, FileMode.Create))
{
await streamStream.CopyToAsync(streamToWriteTo);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occur");
Console.WriteLine(ex.ToString());
}
}
}
}
You will find the image in this folder.
Users/[current user name]/AppData/Local/Packages/[Application package name]/LocalState/Images

Categories