Hi,

I am working on a small application that uses a WebClient to download an XML file via an API call.

Just downloading the file is fine, that all works but I really wanted some way to show the download progress to the end user.

Searching on the net I found a small application which shows a Download ProgressBar during the download of a file, brilliant I thought, that will do it.

Having run this app, it does work fine when downloading a regular file from a regular URL but will not work when I enter my API call URL. It throws an exception because there are illegal characters in the filename.

Here is the code of the small app:-

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace DownloadProgressBar1
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
		{
			// the URL to download the file from
			string sUrlToReadFileFrom = textBoxSourceFile.Text;
			// the path to write the file to
			int iLastIndex = sUrlToReadFileFrom.LastIndexOf('/');
			string sDownloadFileName = sUrlToReadFileFrom.Substring(iLastIndex + 1, (sUrlToReadFileFrom.Length - iLastIndex - 1));
			string sFilePathToWriteFileTo = textBoxDestinationFolder.Text + "\\" + sDownloadFileName;

			// first, we need to get the exact size (in bytes) of the file we are downloading
			Uri url = new Uri(sUrlToReadFileFrom);
			System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
			System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
			response.Close();
			// gets the size of the file in bytes
			Int64 iSize = response.ContentLength;

			// keeps track of the total bytes downloaded so we can update the progress bar
			Int64 iRunningByteTotal = 0;

			// use the webclient object to download the file
			using (System.Net.WebClient client = new System.Net.WebClient())
			{
				// open the file at the remote URL for reading
				using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
				{
					// using the FileStream object, we can write the downloaded bytes to the file system
					using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
					{
						// loop the stream and get the file into the byte buffer
						int iByteSize = 0;
						byte[] byteBuffer = new byte[iSize];
						while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
						{
							// write the bytes to the file system at the file path specified
							streamLocal.Write(byteBuffer, 0, iByteSize);
							iRunningByteTotal += iByteSize;

							// calculate the progress out of a base "100"
							double dIndex = (double)(iRunningByteTotal);
							double dTotal = (double)byteBuffer.Length;
							double dProgressPercentage = (dIndex / dTotal);
							int iProgressPercentage = (int)(dProgressPercentage * 100);

							// update the progress bar
							backgroundWorker1.ReportProgress(iProgressPercentage);
						}

						// clean up the file stream
						streamLocal.Close();
					}

					// close the connection to the remote server
					streamRemote.Close();
				}
			}
		}

		private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			progressBar1.Value = e.ProgressPercentage;
		}

		private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			MessageBox.Show("File download complete");
		}

		private void btnTestDownload_Click(object sender, EventArgs e)
		{
			if (textBoxSourceFile.Text.Length == 0)
			{
				MessageBox.Show("Please enter a source file");
				return;
			}

			if (textBoxDestinationFolder.Text.Length == 0)
			{
				MessageBox.Show("Please enter a destination file");
			}

			backgroundWorker1.RunWorkerAsync();
		}
	}
}

An example of the API call that I am making is below, it returns the value in XML format.

http://open-api.cafepress.com/product.listDeepByStore.cp?v=3&location=GB&appKey=xxxx&storeId=xxxx&page=0&pageSize=150

I have 'xxxx'd out private info for security reasons.

Any pointers to getting this to work would be appreciated, or an alternative where I could just show a loading.gif while the file is being downloaded, would be greatly appreciated.

Kind regards..,

MT

What illegal characters are throwing the exception?

I found the problem shortly after posting the thread.

I changed the line below, which was creating the file name from the URL, in the case of a regular URL that points to an actual file with an extension i.e.

http://www.example.com/file.ext

The original line does work as it should, saving the file as 'file.ext'.

Although because my URL is an API call it is not fully formed, it just returns the XML output.

string sDownloadFileName = sUrlToReadFileFrom.Substring(iLastIndex + 1, (sUrlToReadFileFrom.Length - iLastIndex - 1));

Below is how I changed the above line, now the procedure save the XML output from the API call as a file with the XML extension.

string sDownloadFileName = "file.xml";

Regards..,

MT

This question has already been answered. Start a new discussion instead.