Hello. How can I implement file reloading using the WebClient class? I tried to set the title:

FileInfo file = new FileInfo(path); wc.Headers.Add(HttpRequestHeader.Range, "bytes=-" + file.Length.ToString()); 

So I’m at the existing, but not until the end of the downloaded file, take its size and substitute it in the "Range" header so that the download starts from this size and to the end. But the download doesn't start at all. Can this be implemented via WebClient? If not, how can this be done via httpwebrequest, if the code is already written under WebClient?

  • "But the download doesn't start at all" - what happens? - Pavel Mayorov 1:09 pm
  • Nothing. paste2.org/x1UUnxV8 Just does not start downloading and displays: "Downloading ..." - kompas
  • I do not see error handling. - Pavel Mayorov pm
  • You call an asynchronous operation — and you need to track not only its successful execution, but also the unsuccessful one. - Pavel Mayorov 1:21 pm
  • Great. And what should error handling look like in this case? - kompas

1 answer 1

The Range header cannot be installed explicitly through the Headers collection: https://msdn.microsoft.com/en-us/library/system.net.webclient.headers.aspx .

When you start downloading the file, you will get a WebException exception with the message

You need to be modified using the appropriate property or method

However, you can create a WebClient descendant by correcting this error in it. I think it’s MyWebClient to replace WebClient with MyWebClient everywhere:

 class MyWebClient: WebClient { private int _position; // установка позиции, откуда будет возобновлено скачивание public void SetFromPosition(int position) { _position = position; } protected override WebRequest GetWebRequest(Uri address) { var request = (HttpWebRequest) base.GetWebRequest(address); // если позиция задана, установим заголовок range легальным способом if (_position > 0) request.AddRange(_position); return request; } } 

Example of use:

 var client = new MyWebClient(); var info = new FileInfo(file); if (info.Exists) { client.SetFromPosition((int)info.Length); } client.DownloadFileAsync(new Uri(url), file); // ... 

Method for resuming file:

 public new void DownloadFile(Uri url, string file) { using (var fs = new FileStream(file, FileMode.Append, FileAccess.Write)) { using (var response = OpenRead(url)) { response.CopyTo(fs); } } } 

An example of loading into a temporary file with the subsequent merging of files:

 var client = new MyWebClient(); string tmpFile = file + ".bak"; // временный файл c.DownloadFileCompleted += (sender, args) => { // дозапись из src в dest using (var dest = new FileStream(file, FileMode.Append, FileAccess.Write)) { using (var src = new FileStream(tmpFile, FileMode.Open, FileAccess.Read)) { src.CopyTo(dest); } } File.Delete(tmpFile); }; var info = new FileInfo(file); if (info.Exists) { client.SetFromPosition((int)info.Length); } c.DownloadFileAsync(new Uri(url), tmpFile); 
  • Schaarno. That's just the result is what I expected - the file is overwritten. But the download from the desired fragment works. - kompas
  • @kompas yes, looked at the sources, DownloadFile really creates a stream with the option FileMode.Create. Then you have to write your DownloadFile method. - kmv
  • Or save it to some other file and then merge them together - kmv
  • @kvm, it is possible, yes. In principle, the resume in the .bak file is also suitable, but how to merge them later? - kompas 1:58 pm
  • @kompas, WebClient has an OpenRead method that gives access to the stream, added an example of how to download a file without overwriting it. - kmv