As I was creating upgrade procedure for few programs of mine I had a need to download file. With progress bar. Most of you can already see a solution: HttpWebRequest
in BackgroundWorker
.
Base idea is creation of HttpWebRequest
, getting it's response as stream and iterating through all bytes until we read them all. Heart of (DoWork
) code is:
var request = (HttpWebRequest)HttpWebRequest.Create(url);
using (var response = (HttpWebResponse)request.GetResponse()) {
using (var stream = response.GetResponseStream()) {
using (var bytes = new MemoryStream()) {
var buffer = new byte[256];
while (bytes.Length < response.ContentLength) {
var read = stream.Read(buffer, 0, buffer.Length);
if (read > 0) {
bytes.Write(buffer, 0, read);
bcwDownload.ReportProgress((int)(bytes.Length * 100 / len));
} else {
break;
}
}
}
}
}
Before we send result back to RunWorkerCompleted
event we need to get file name that was actually delivered. While this step is optional, I find it especially useful if there are some redirections on web site (e.g. pointing you to newer version of file):
string fileName = response.ResponseUri.Segments[response.ResponseUri.Segments.Length - 1];
e.Result = new DownloadResult(fileName, bytes.ToArray());
P.S. Do notice that DownloadResult is our own class - there is no such class in .NET Framework.
In RunWorkerCompleted
we only must save file as such:
var res = (DownloadResult)e.Result;
var file = new FileInfo(res.FileName);
using (var frm = new SaveFileDialog() { FileName = file.Name }) {
if (frm.ShowDialog(this) == DialogResult.OK) {
File.WriteAllBytes(frm.FileName, res.Bytes);
MessageBox.Show(this, "Done.", "Something", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
And with that you have your file downloaded.
Full source code (with all missing parts of code) is available for download.