472

What is a simple way of downloading a file from a URL path?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vbroto
  • 6,088
  • 3
  • 22
  • 12
  • 18
    Have a look at System.Net.WebClient – seanb Nov 21 '08 at 03:00
  • Please be aware that almost all of the answers may work, but the will fail in production code and cause hours (days?) of troubleshooting headaches. For a toy project, no worries. For production code, web programming needs lots of error handling, diagnostics and sometimes retry logic. – snj Jul 06 '23 at 23:27

19 Answers19

605
using (var client = new WebClient())
{
    client.DownloadFile("http://example.com/file/song/a.mpeg", "a.mpeg");
}
Bryan Legend
  • 6,790
  • 1
  • 59
  • 60
Raj Kumar
  • 6,970
  • 5
  • 30
  • 40
  • 38
    The best solution ever but I would like to add 1 important line 'client.Credentials = new NetworkCredential("UserName", "Password");' – NoWar Sep 07 '16 at 13:11
  • 6
    A welcome side effect: This method also supports local files as 1st parameter – oo_dev Aug 22 '17 at 08:35
  • Though I think that WebClient seems like a much more straightforward and simple solution. – StormsEngineering Oct 01 '19 at 23:17
  • 7
    @copa017: Or a dangerous one, if, for example, the URL is user-supplied and the C# code runs on a web server. – Heinzi Apr 25 '20 at 09:25
  • Make it Async: WebClient client = new WebClient(); await client.DownloadFileTaskAsync(new Uri("http://somesite.com/myfile.txt"), "mytxtFile.txt"); – M22 May 23 '21 at 13:33
  • @M22 the async method does not return a Task which means you can't await it. Depending on your code your program might exit before the download is complete, leaving it in a corrupt state. – Shashank Shekhar Jun 05 '21 at 00:16
  • 1
    @ShashankShekhar https://ibb.co/1Xf0nrD ```c# static void Main(string[] args) { DownloadFileAsync().GetAwaiter(); Console.WriteLine("File loaded"); Console.Read(); } private static async Task DownloadFileAsync() { WebClient client = new WebClient(); await client.DownloadFileTaskAsync(new Uri("http://somesite.com/myfile.txt"), "mytxtFile.txt"); } ``` Task can be concurrent, not neccesary a new thread. – M22 Jun 05 '21 at 21:38
  • 13
    WebRequest, WebClient, and ServicePoint are obsolete in **.Net 6** link --> https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/6.0/webrequest-deprecated – Akbar Asghari Jan 10 '22 at 18:44
  • 5
    @AkbarAsghari is correct. See [my answer below](https://stackoverflow.com/a/71949994/5172807) for example with HttpClient class. – Davide Briscese Apr 21 '22 at 06:46
239

Include this namespace

using System.Net;

Download Asynchronously and put a ProgressBar to show the status of the download within the UI Thread Itself

private void BtnDownload_Click(object sender, RoutedEventArgs e)
{
    using (WebClient wc = new WebClient())
    {
        wc.DownloadProgressChanged += wc_DownloadProgressChanged;
        wc.DownloadFileAsync (
            // Param1 = Link of file
            new System.Uri("http://www.sayka.com/downloads/front_view.jpg"),
            // Param2 = Path to save
            "D:\\Images\\front_view.jpg"
        );
    }
}
// Event to track the progress
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    progressBar.Value = e.ProgressPercentage;
}
Abdul Saleem
  • 10,098
  • 5
  • 45
  • 45
94

Use System.Net.WebClient.DownloadFile:

string remoteUri = "http://www.contoso.com/library/homepage/images/";
string fileName = "ms-banner.gif", myStringWebResource = null;

// Create a new WebClient instance.
using (WebClient myWebClient = new WebClient())
{
    myStringWebResource = remoteUri + fileName;
    // Download the Web resource and save it into the current filesystem folder.
    myWebClient.DownloadFile(myStringWebResource, fileName);        
}
Chris Lee
  • 158
  • 6
vbroto
  • 6,088
  • 3
  • 22
  • 12
78

WebRequest, WebClient, and ServicePoint are obsolete from .NET 6 (source - 11/2021).

Use the System.Net.Http.HttpClient class instead:

using (var client = new HttpClient())
{
    using (var s = client.GetStreamAsync("https://via.placeholder.com/150"))
    {
        using (var fs = new FileStream("localfile.jpg", FileMode.OpenOrCreate))
        {
            s.Result.CopyTo(fs);
        }
    }
}

Async version of the same code:

using var client = new HttpClient();
using var s = await client.GetStreamAsync("https://via.placeholder.com/150");
using var fs = new FileStream("localfile.jpg", FileMode.OpenOrCreate);
await s.CopyToAsync(fs);

Davide Briscese
  • 1,161
  • 8
  • 18
48
using System.Net;

WebClient webClient = new WebClient();
webClient.DownloadFile("http://mysite.com/myfile.txt", @"c:\myfile.txt");
petrzjunior
  • 704
  • 20
  • 26
  • 38
    Welcome to SO! Generally it's not a good idea to post a low-quality answer to an existing and old question that already has highly upvoted answers. – ThiefMaster Jun 29 '13 at 16:25
23

Complete class to download a file while printing status to console.

using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Threading;

class FileDownloader
{
    private readonly string _url;
    private readonly string _fullPathWhereToSave;
    private bool _result = false;
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(0);

    public FileDownloader(string url, string fullPathWhereToSave)
    {
        if (string.IsNullOrEmpty(url)) throw new ArgumentNullException("url");
        if (string.IsNullOrEmpty(fullPathWhereToSave)) throw new ArgumentNullException("fullPathWhereToSave");

        this._url = url;
        this._fullPathWhereToSave = fullPathWhereToSave;
    }

    public bool StartDownload(int timeout)
    {
        try
        {
            System.IO.Directory.CreateDirectory(Path.GetDirectoryName(_fullPathWhereToSave));

            if (File.Exists(_fullPathWhereToSave))
            {
                File.Delete(_fullPathWhereToSave);
            }
            using (WebClient client = new WebClient())
            {
                var ur = new Uri(_url);
                // client.Credentials = new NetworkCredential("username", "password");
                client.DownloadProgressChanged += WebClientDownloadProgressChanged;
                client.DownloadFileCompleted += WebClientDownloadCompleted;
                Console.WriteLine(@"Downloading file:");
                client.DownloadFileAsync(ur, _fullPathWhereToSave);
                _semaphore.Wait(timeout);
                return _result && File.Exists(_fullPathWhereToSave);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Was not able to download file!");
            Console.Write(e);
            return false;
        }
        finally
        {
            this._semaphore.Dispose();
        }
    }

    private void WebClientDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        Console.Write("\r     -->    {0}%.", e.ProgressPercentage);
    }

    private void WebClientDownloadCompleted(object sender, AsyncCompletedEventArgs args)
    {
        _result = !args.Cancelled;
        if (!_result)
        {
            Console.Write(args.Error.ToString());
        }
        Console.WriteLine(Environment.NewLine + "Download finished!");
        _semaphore.Release();
    }

    public static bool DownloadFile(string url, string fullPathWhereToSave, int timeoutInMilliSec)
    {
        return new FileDownloader(url, fullPathWhereToSave).StartDownload(timeoutInMilliSec);
    }
}

Usage:

static void Main(string[] args)
{
    var success = FileDownloader.DownloadFile(fileUrl, fullPathWhereToSave, timeoutInMilliSec);
    Console.WriteLine("Done  - success: " + success);
    Console.ReadLine();
}
Jonas_Hess
  • 1,874
  • 1
  • 22
  • 32
15

Try using this:

private void downloadFile(string url)
{
     string file = System.IO.Path.GetFileName(url);
     WebClient cln = new WebClient();
     cln.DownloadFile(url, file);
}
Surendra Shrestha
  • 1,035
  • 12
  • 21
12

Also you can use DownloadFileAsync method in WebClient class. It downloads to a local file the resource with the specified URI. Also this method does not block the calling thread.

Sample:

    webClient.DownloadFileAsync(new Uri("http://www.example.com/file/test.jpg"), "test.jpg");

For more information:

http://csharpexamples.com/download-files-synchronous-asynchronous-url-c/

turgay
  • 438
  • 4
  • 7
11

Check for a network connection using GetIsNetworkAvailable() to avoid creating empty files when not connected to a network.

if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
    using (System.Net.WebClient client = new System.Net.WebClient())
    {                        
          client.DownloadFileAsync(new Uri("http://www.examplesite.com/test.txt"),
          "D:\\test.txt");
    }                  
}
haZya
  • 285
  • 4
  • 14
  • I would suggest *not* using `GetIsNetworkAvailable()` as, in my experience, returns too many false-positives. – Cherona Jan 21 '20 at 10:19
  • Unless you are in a computer network such as a LAN, `GetIsNetworkAvailable()` would always return correctly. In such a case you can use `System.Net.WebClient().OpenRead(Uri)` method to see if it returns when given a default url. See [WebClient.OpenRead()](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.openread?view=netframework-4.8) – haZya Jan 21 '20 at 18:04
11

WebClient is obsolete

If you want to download to a file avoid first reading to memory by using ResponseHeadersRead like this:

static public async Task HttpDownloadFileAsync(HttpClient httpClient, string url, string fileToWriteTo) {
  using HttpResponseMessage response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
  using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync(); 
  using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create); 
  await streamToReadFrom.CopyToAsync(streamToWriteTo);
}

Above code is more of an outline, adding correct error/exception handling is not trivial, also progress report is not trivial, as is Disposing.

I came up with a set of C# 9.0 extension classes for DownoadFileAsync, GetToStringAsync and PostToStringAsync

namespace System.Net.Http {

  // HttpResponse is in one of 3 states:
  // - ResponseMessageInfo is object && ResponseMessageInfo.IsSuccessStatusCode -> success, inspect ResponseMessageInfo for StatusCode etc
  // - ResponseMessageInfo is object && !ResponseMessageInfo.IsSuccessStatusCode -> failure, inspect ResponseMessageInfo for StatusCode, ReasonPhrase etc
  // - ResponseMessageInfo is null -> exception, inspect ExceptionInfo fields
  public record HttpResponse {

    // copies of HttpRequestMessage and HttpResponseMessage which do not have the content and do not need to be disposed
    public record HttpRequestMessageInfo(HttpRequestHeaders Headers, HttpMethod Method, HttpRequestOptions Options, Uri? RequestUri, Version Version, HttpVersionPolicy VersionPolicy);
    public record HttpResponseMessageInfo(HttpResponseHeaders Headers, bool IsSuccessStatusCode, string? ReasonPhrase, HttpRequestMessageInfo RequestMessage, HttpStatusCode StatusCode, HttpResponseHeaders TrailingHeaders, Version Version);

    // holds Http exception information
    public record HttpExceptionInfo(HttpRequestMessageInfo HttpRequestMessage, string ErrorMessage, WebExceptionStatus? WebExceptionStatus);

    // if ResponseMessageInfo is null ExceptionInfo is not and vice versa
    public HttpResponseMessageInfo? ResponseMessageInfo { get; init; }
    public HttpExceptionInfo? ExceptionInfo { get; init; }

    public HttpResponse(HttpRequestMessage requestMessage, HttpResponseMessage responseMessage) {
      var requestMessageInfo = new HttpRequestMessageInfo(requestMessage.Headers, requestMessage.Method, requestMessage.Options, requestMessage.RequestUri, requestMessage.Version, requestMessage.VersionPolicy);
      ResponseMessageInfo = new(responseMessage.Headers, responseMessage.IsSuccessStatusCode, responseMessage.ReasonPhrase, requestMessageInfo, responseMessage.StatusCode, responseMessage.TrailingHeaders, responseMessage.Version);
      ExceptionInfo = null;
    }

    public HttpResponse(HttpRequestMessage requestMessage, Exception exception) {
      ResponseMessageInfo = null;
      var requestMessageInfo = new HttpRequestMessageInfo(requestMessage.Headers, requestMessage.Method, requestMessage.Options, requestMessage.RequestUri, requestMessage.Version, requestMessage.VersionPolicy);

      if (exception is WebException ex1 && ex1.Status == WebExceptionStatus.ProtocolError) {
        using HttpWebResponse? httpResponse = (HttpWebResponse?)ex1.Response;
        ExceptionInfo = new(requestMessageInfo, httpResponse?.StatusDescription ?? "", ex1.Status);
      } 
      else if (exception is WebException ex2) ExceptionInfo = new(requestMessageInfo, ex2.FullMessage(), ex2.Status);
      else if (exception is TaskCanceledException ex3 && ex3.InnerException is TimeoutException) ExceptionInfo = new(requestMessageInfo, ex3.InnerException.FullMessage(), WebExceptionStatus.Timeout);
      else if (exception is TaskCanceledException ex4) ExceptionInfo = new(requestMessageInfo, ex4.FullMessage(), WebExceptionStatus.RequestCanceled);
      else ExceptionInfo = new(requestMessageInfo, exception.FullMessage(), null);
    }

    public override string ToString() {
      if (ResponseMessageInfo is object) {
        var msg = ResponseMessageInfo.IsSuccessStatusCode ? "Success" : "Failure";
        msg += $" {Enum.GetName(typeof(HttpStatusCode), ResponseMessageInfo.StatusCode)}";
        if (ResponseMessageInfo.ReasonPhrase is object) msg += $" {ResponseMessageInfo.ReasonPhrase}";
        return msg;

      } else if (ExceptionInfo is object) {
        var msg = "Failure";
        msg += $" {ExceptionInfo.ErrorMessage}";
        if (ExceptionInfo.WebExceptionStatus is object) msg += $" {Enum.GetName(typeof(WebExceptionStatus), ExceptionInfo.WebExceptionStatus)}";
        return msg;
      }
      return "NA"; // never reach here
    }
  }


  public static class ExtensionMethods {

    // progressCallback recieves (bytesRecieved, percent, speedKbSec) and can return false to cancell download
    public static async Task<(bool success, HttpResponse httpResponse)> DownloadFileAsync(this HttpClient httpClient, Uri requestUri, string fileToWriteTo, CancellationTokenSource? cts = null, Func<long, int, float, bool>? progressCallback = null) {
      var httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = requestUri };
      var created = false;

      try {
        var cancellationToken = cts?.Token ?? default;

        using HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (false, new(httpRequestMessage, httpResponseMessage));
        var contentLength = httpResponseMessage.Content.Headers.ContentLength;

        using Stream streamToReadFrom = await httpResponseMessage.Content.ReadAsStreamAsync();
        using Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create);
        created = true;

        var buffer = new byte[81920]; 
        var bytesRecieved = (long)0;
        var stopwatch = Stopwatch.StartNew();
        int bytesInBuffer;
        while ((bytesInBuffer = await streamToReadFrom.ReadAsync(buffer, cancellationToken)) != 0) {
          await streamToWriteTo.WriteAsync(buffer.AsMemory(0, bytesInBuffer), cancellationToken);
          bytesRecieved += bytesInBuffer;
          if (progressCallback is object) {
            var percent = contentLength is object && contentLength != 0 ? (int)Math.Floor(bytesRecieved / (float)contentLength * 100.0) : 0;
            var speedKbSec = (float)((bytesRecieved / 1024.0) / (stopwatch.ElapsedMilliseconds / 1000.0));
            var proceed = progressCallback(bytesRecieved, percent, speedKbSec);
            if (!proceed) {
              httpResponseMessage.ReasonPhrase = "Callback cancelled download";
              httpResponseMessage.StatusCode = HttpStatusCode.PartialContent;
              return (false, new(httpRequestMessage, httpResponseMessage));
            }
          }
        }

        return (true, new(httpRequestMessage, httpResponseMessage));
      }
      catch (Exception ex) {
        if (created) try { File.Delete(fileToWriteTo); } catch { };
        return (false, new(httpRequestMessage, ex));
      }
    }

    public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> GetToStringAsync(this HttpClient httpClient, Uri requestUri, CancellationTokenSource? cts = null) {
      var httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = requestUri };
      try {
        var cancellationToken = cts?.Token ?? default;
        using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (null, new(httpRequestMessage, httpResponseMessage));
        
        var responseAsString = await httpResponseMessage.Content.ReadAsStringAsync();
        return (responseAsString, new(httpRequestMessage, httpResponseMessage));
      }
      catch (Exception ex) {
        return (null, new(httpRequestMessage, ex)); ;
      }
    }

    public static async Task<(string? ResponseAsString, HttpResponse httpResponse)> PostToStringAsync(this HttpClient httpClient, Uri requestUri, HttpContent postBuffer, CancellationTokenSource? cts = null) {
      var httpRequestMessage = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = requestUri, Content = postBuffer };
      try {
        var cancellationToken = cts?.Token ?? default;
        using var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);
        if (!httpResponseMessage.IsSuccessStatusCode) return (null, new(httpRequestMessage, httpResponseMessage));

        var responseAsString = await httpResponseMessage.Content.ReadAsStringAsync();
        return (responseAsString, new(httpRequestMessage, httpResponseMessage));
      }
      catch (Exception ex) {
        return (null, new(httpRequestMessage, ex));
      }
    }

  }
}

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
      return msg;
    }
  }
}

To use:

// download to file
var lastPercent = 0;
bool progressCallback(long bytesRecieved, int percent, float speedKbSec) {
  if (percent > lastPercent) {
    lastPercent = percent;
    Log($"Downloading... {percent}% {speedKbSec/1024.0:0.00}Mbps");
  }
  return true;
}

var (success, httpResponse) = await httpClient.DownloadFileAsync(
  new(myUrlString), 
  localFileName, 
  null, // CancellationTokenSource 
  progressCallback
);

if (success) {
  // file downloaded to localFile, httpResponse.ResponseMessageInfo contain 
  // extra information ie headers and status code

} else {
  Log(httpResponse.ToString()); // human friendly error information
  // if httpResponse.ResponseMessageInfo is object then server refused the request - 
  // examine httpResponse.ResponseMessageInfo.HttpStatusCode etc
  // else we had a Http exception - examine httpResponse.ExceptionInfo 
}


// Http get
var (responseAsString, httpResponse) = await httpClient.GetToStringAsync(url);
if (responseAsString is object) {
  // responseAsString contains the string response from the server

} else {
  // as for DownloadFileAsync
}


// http post
var postBuffer = new StringContent(jsonInString, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");
var (responseAsString, httpResponse) = await httpClient.PostToStringAsync(url, postBuffer);

if (responseAsString is object) {
  // responseAsString contains the string response from the server

} else {
  Log(httpResponse.ToString()); // human friendly error informaiton
  // as for DownloadFileAsync
}
kofifus
  • 17,260
  • 17
  • 99
  • 173
6

This is the solution I used recently for .NET 6 or greater.

using var httpClient = new HttpClient();

var tempPath = Path.GetTempFileName();

await using var s = await httpClient.GetStreamAsync(pdfFilePath);

await using var fs = File.OpenWrite(tempPath);

await s.CopyToAsync(fs);
n1k1ch
  • 2,594
  • 3
  • 31
  • 35
Kevin Smith
  • 13,746
  • 4
  • 52
  • 77
5

Below code contain logic for download file with original name

private string DownloadFile(string url)
    {

        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
        string filename = "";
        string destinationpath = Environment;
        if (!Directory.Exists(destinationpath))
        {
            Directory.CreateDirectory(destinationpath);
        }
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result)
        {
            string path = response.Headers["Content-Disposition"];
            if (string.IsNullOrWhiteSpace(path))
            {
                var uri = new Uri(url);
                filename = Path.GetFileName(uri.LocalPath);
            }
            else
            {
                ContentDisposition contentDisposition = new ContentDisposition(path);
                filename = contentDisposition.FileName;

            }

            var responseStream = response.GetResponseStream();
            using (var fileStream = File.Create(System.IO.Path.Combine(destinationpath, filename)))
            {
                responseStream.CopyTo(fileStream);
            }
        }

        return Path.Combine(destinationpath, filename);
    }
3

Update: WebClinet is obsolete and recommended to use HttpClient instead. Here’s the simplest possible example of downloading a file using HttpClient.

var httpClient = new HttpClient();
using var stream = await httpClient.GetStreamAsync(remoteUri);
using var fileStream = new FileStream(FilePath, FileMode.CreateNew);
await stream.CopyToAsync(fileStream);

Example console app is as follows:

namespace DownloadFile
{
    public class Program
    {
        public static void Main()
        {
            Download("https://code.jquery.com/jquery-3.7.0.js").Wait();
        }
        public static async Task Download(string remoteUri)
        {
            try
            {
                // path where download file to be saved, with filename, here I have taken file name from supplied remote url
                string FilePath = Path.Combine(Directory.GetCurrentDirectory(), "tempdownload", Path.GetFileName(remoteUri));
                var httpClient = new HttpClient();

                if (!Directory.Exists("tempdownload"))
                {
                    Directory.CreateDirectory("tempdownload");
                }
                using var stream = await httpClient.GetStreamAsync(remoteUri);
                using var fileStream = new FileStream(FilePath, FileMode.CreateNew);
                await stream.CopyToAsync(fileStream);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

Downloading file using obsolete WebClient.DownloadFileAsync. It is available in System.Net namespace and it supports .net core as well.

Here is the sample code to download the file.

using System;
using System.IO;
using System.Net;
using System.ComponentModel;
                    
public class Program
{
    public static void Main()
    {
        new Program().Download("ftp://localhost/test.zip");
    }
    public void Download(string remoteUri)
    {
        string FilePath = Directory.GetCurrentDirectory() + "/tepdownload/" + Path.GetFileName(remoteUri); // path where download file to be saved, with filename, here I have taken file name from supplied remote url
        using (WebClient client = new WebClient())
        {
            try
            {
                if (!Directory.Exists("tepdownload"))
                {
                    Directory.CreateDirectory("tepdownload");
                }
                Uri uri = new Uri(remoteUri);
                //password username of your file server eg. ftp username and password
                client.Credentials = new NetworkCredential("username", "password");
                //delegate method, which will be called after file download has been complete.
                client.DownloadFileCompleted += new AsyncCompletedEventHandler(Extract);
                //delegate method for progress notification handler.
                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgessChanged);
                // uri is the remote url where filed needs to be downloaded, and FilePath is the location where file to be saved
                client.DownloadFileAsync(uri, FilePath);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
    public void Extract(object sender, AsyncCompletedEventArgs e)
    {
        Console.WriteLine("File has been downloaded.");
    }
    public void ProgessChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        Console.WriteLine($"Download status: {e.ProgressPercentage}%.");
    }
}

With above code file will be downloaded inside tepdownload folder of the project's directory. Please read comment in code to understand what above code do.

Albert Einstein
  • 7,472
  • 8
  • 36
  • 71
3

In the event that you need to set Headers and Cookies to download a file, you will need to do things slightly differently. Here is an example...

// Pass in the HTTPGET URL, Full Path w/Filename, and a populated Cookie Container (optional)
private async Task DownloadFileRequiringHeadersAndCookies(string getUrl, string fullPath, CookieContainer cookieContainer, CancellationToken cancellationToken)
{
    cookieContainer ??= new CookieContainer();  // TODO: FILL ME AND PASS ME IN

    using (var handler = new HttpClientHandler()
    {
        UseCookies = true,
        CookieContainer = cookieContainer, // This will, both, use the cookies passed in, and update/create cookies from the response
        ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true, // use only if it gets angry about the SSL endpoints
        AllowAutoRedirect = true,
    })
    {
        using (var client = new HttpClient(handler))
        {
            SetHeaders(client);

            using (var response = await client.GetAsync(getUrl, cancellationToken))
            {
                if (response.IsSuccessStatusCode)
                {
                    var bytes = await response.Content.ReadAsByteArrayAsync(cancellationToken);
                    await File.WriteAllBytesAsync(fullPath, bytes, cancellationToken); // This overwrites the file
                }
                else
                {
                    // TODO: HANDLE ME
                    throw new FileNotFoundException();
                }
            }
        }
    }
}

And, to add the Headers you need with this...

private void SetHeaders(HttpClient client)
{
    // TODO: SET ME
    client.DefaultRequestHeaders.Connection.Add("keep-alive");
    client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...");
    client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9, ...");
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
    client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
    client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US"));
    client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("en", .9));
    ...
}

ASIDE: You can fill the CookieContainer by:

  1. Looping through the cookies of a previous Response.
    • This response could be from HttpAgilityPack, or WebClient, or Puppeteer (lots of options)
  2. Manually entries (from config values or hard coded values).
Cryptc
  • 2,959
  • 1
  • 18
  • 18
2

You may need to know the status and update a ProgressBar during the file download or use credentials before making the request.

Here it is, an example that covers these options. Lambda notation and String interpolation has been used:

using System.Net;
// ...

using (WebClient client = new WebClient()) {
    Uri ur = new Uri("http://remotehost.do/images/img.jpg");

    //client.Credentials = new NetworkCredential("username", "password");
    String credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes("Username" + ":" + "MyNewPassword"));
    client.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";

    client.DownloadProgressChanged += (o, e) =>
    {
        Console.WriteLine($"Download status: {e.ProgressPercentage}%.");

        // updating the UI
        Dispatcher.Invoke(() => {
            progressBar.Value = e.ProgressPercentage;
        });
    };

    client.DownloadDataCompleted += (o, e) => 
    {
        Console.WriteLine("Download finished!");
    };

    client.DownloadFileAsync(ur, @"C:\path\newImage.jpg");
}
Kreshnik
  • 2,661
  • 5
  • 31
  • 39
  • Some comments about the purpose of your code statements would be helpful, for those who are unfamiliar with asynchronous operations and cross-thread calls. – Suncat2000 Jan 22 '21 at 12:28
2
static void Main(string[] args)
        {
            DownloadFileAsync().GetAwaiter();
 
            Console.WriteLine("File was downloaded");
            Console.Read();
        }
 
        private static async Task DownloadFileAsync()
        {
            WebClient client = new WebClient();
            await client.DownloadFileTaskAsync(new Uri("http://somesite.com/myfile.txt"), "mytxtFile.txt");
        }
M22
  • 543
  • 5
  • 10
1

In .NET Core MVC, you can sometimes do it as simply as:

public async Task<ActionResult> DownloadUrl(string url) {
    return Redirect(url);
}

This probably assumes that the MIME type you're trying to download is set to be downloadable by the browser (e.g. .mp4), so it doesn't try to redirect to a webpage.

Cryptc
  • 2,959
  • 1
  • 18
  • 18
1

Check this out too. This code has been improved to ensure its successful execution by adding the required using directives for the System.IO and System.Net namespaces.

using (WebClient client = new WebClient())
{
    using (Stream stream = client.OpenRead("https://test.com/110.txt"))
    {
        using (FileStream fileStream = File.Create("C:\\Downloads\\110.txt"))
        {
            stream.CopyTo(fileStream);
        }
    }
}
Freeman
  • 9,464
  • 7
  • 35
  • 58
0

This is my solution, it works fine:

public static void DownloadFile(string url, string pathToSaveFile)
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            // or: ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

            using (WebDownload client = new WebDownload())
            {
                client.Headers["User-Agent"] = "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36";
                client.DownloadFile(new Uri(url), pathToSaveFile);
            }
        }
    
    public class WebDownload : WebClient
        {
            protected override WebRequest GetWebRequest(Uri address)
            {
                HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
                if (request != null)
                {
                    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                }
                return request;
            }
        }
O Thạnh Ldt
  • 1,103
  • 10
  • 11