HttpClient: Downloading to a Local File
Downloading content to a local file is a common thing to do. The current version of HttpClient doesn’t yet provide out of the box support for saving content to a file but this sample shows how to extend HttpClient with new ways of reading content retrieved using HttpClient. Please see List of ASP.NET Web API and HttpClient Samples for the complete sample solution.
ReadAs Extension Methods
The HttpContent class contains content to be sent to a client (in the case of PUT, POST, etc.) as well as data being read from the server in a response. The basic System.Net.Http NuGet package provides support for reading the content as a stream, a string, or a byte array using one of
- HttpContent.ReadAsStringAsync
- HttpContent.ReadAsStreamAsync
- HttpContent.ReadAsByteArrayAsync
The way to extend how an HttpContent can be consumed is through the ReadAs* extension methods. The System.Net.Formatter NuGet package offers a set of additional ReadAs* methods, for reading and deserializing data at the same time. This sample shows how to add a simple ReadAsFileAsync extension method but the floor is open for any number of ways of reading the content.
LoadIntobufferAsync
In general, when you read data from an HttpContent it is consumed meaning that it can’t be read again (like when you read a non-seekable stream). However, if you want to be able to read the content multiple times then you can use the LoadIntoBufferAsync method to do that. This will cause the content to get read into an internal buffer so that it can consumed multiple times without retrieving it again over the network.
1: static void Main(string[] args)
2: {
3: HttpClient client = new HttpClient();
4:
5: // Send asynchronous request
6: client.GetAsync(_address).ContinueWith(
7: (requestTask) =>
8: {
9: // Get HTTP response from completed task.
10: HttpResponseMessage response = requestTask.Result;
11:
12: // Check that response was successful or throw exception
13: response.EnsureSuccessStatusCode();
14:
15: // Read content into buffer
16: response.Content.LoadIntoBufferAsync();
17:
18: // The content can now be read multiple times using any ReadAs* extension method
19: });
20:
21: Console.WriteLine("Hit ENTER to exit...");
22: Console.ReadLine();
23: }
ReadAsFileAsync
First we make the ReadAsFileAsync extension method on HttpContent to provide support for reading the content and storing it directly in a local file:
1: public static class HttpContentExtensions
2: {
3: public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite)
4: {
5: string pathname = Path.GetFullPath(filename);
6: if (!overwrite && File.Exists(filename))
7: {
8: throw new InvalidOperationException(string.Format("File {0} already exists.", pathname));
9: }
10:
11: FileStream fileStream = null;
12: try
13: {
14: fileStream = new FileStream(pathname, FileMode.Create, FileAccess.Write, FileShare.None);
15: return content.CopyToAsync(fileStream).ContinueWith(
16: (copyTask) =>
17: {
18: fileStream.Close();
19: });
20: }
21: catch
22: {
23: if (fileStream != null)
24: {
25: fileStream.Close();
26: }
27:
28: throw;
29: }
30: }
31: }
Downloading a Google Map
Finally we put the two together – in this case we download an image from Google Maps and open it up in the default image viewer (if you don’t have an image viewer then opening the downloaded image will fail but that doesn’t change the download part):
1: /// <summary>
2: /// Downloads a Redmond map from Google Map, saves it as a file and opens the default viewer.
3: /// </summary>
4: class Program
5: {
6: static string _address = "https://maps.googleapis.com/maps/api/staticmap?center=Redmond,WA&zoom=14&size=400x400&sensor=false";
7:
8: static void Main(string[] args)
9: {
10: HttpClient client = new HttpClient();
11:
12: // Send asynchronous request
13: client.GetAsync(_address).ContinueWith(
14: (requestTask) =>
15: {
16: // Get HTTP response from completed task.
17: HttpResponseMessage response = requestTask.Result;
18:
19: // Check that response was successful or throw exception
20: response.EnsureSuccessStatusCode();
21:
22: // Read response asynchronously and save to file
23: response.Content.ReadAsFileAsync("output.png", true).ContinueWith(
24: (readTask) =>
25: {
26: Process process = new Process();
27: process.StartInfo.FileName = "output.png";
28: process.Start();
29: });
30: });
31:
32: Console.WriteLine("Hit ENTER to exit...");
33: Console.ReadLine();
34: }
35: }
Have fun!
Henrik
del.icio.us Tags: asp.net,webapi,mvc,rest,httpclient
Comments
Anonymous
July 25, 2012
Thanks for the sample. But I do not see the extension method used here. I am missing something.Anonymous
November 03, 2012
Raghu: public static Task ReadAsFileAsync(this HttpContent content, string filename, bool overwrite) That is an used in the download a google map sectionAnonymous
March 15, 2014
I want to POST large files to a server using HttpClient. Httpclient has a default timeout of 100 seconds. I do not want to set timeout to infinite. My httpclient should not timeout under normal circumstances and if the httpclient is not able to write data to the request stream it should timeout after say 4 minutes. Any ideas on how accomplish this ? ThanksAnonymous
June 17, 2015
can you please explain httpclient means