Wait until file is downloaded from URL via webClient

Muflix picture Muflix · Jan 29, 2015 · Viewed 9.6k times · Source

I have struggle with downloading few MB excel file from URL and then work with it. Im using VS2010 so i cant use await keyword. My code follows:

using (WebClient webClient = new WebClient())
                {
                    // setting Windows Authentication
                    webClient.UseDefaultCredentials = true;
                    // event fired ExcelToCsv after file is downloaded
                    webClient.DownloadFileCompleted += (sender, e) => ExcelToCsv(fileName);
                    // start download
                    webClient.DownloadFileAsync(new Uri("http://serverx/something/Export.ashx"), exportPath);
                }

The line in ExcelToCsv() method

using (FileStream stream = new FileStream(filePath, FileMode.Open))

Throws me an error:

System.IO.IOException: The process cannot access the file because it is being used by another process.

I tried webClient.DownloadFile() only without an event but it throws same error. Same error is throwed if i do not dispose too. What can i do ?

Temporary workaround may be Sleep() method but its not bullet proof.

Thank you

EDIT: I tried second approach with standard handling but i have mistake in the code

  using (WebClient webClient = new WebClient())
                {
                    // nastaveni ze webClient ma pouzit Windows Authentication
                    webClient.UseDefaultCredentials = true;
                    // <--- I HAVE CONVERT ASYNC ERROR IN THIS LINE
                    webClient.DownloadFileCompleted += new DownloadDataCompletedEventHandler(HandleDownloadDataCompleted);

                    // spusteni stahovani
                    webClient.DownloadFile(new Uri("http://czprga2001/Logio_ZelenyKyblik/Export.ashx"), TempDirectory + PSFileName);
                }

public delegate void DownloadDataCompletedEventHandler(string fileName);
        public event DownloadDataCompletedEventHandler DownloadDataCompleted;
        static void HandleDownloadDataCompleted(string fileName)
        { 
            ExcelToCsv(fileName);
        }

EDIT: approach 3 I tried this code

while (true)
                {
                    if (isFileLocked(downloadedFile))
                    {
                        System.Threading.Thread.Sleep(5000); //wait 5s
                        ExcelToCsv(fileName);
                        break;
                    }
                }

and it seems that it is never accessible :/ I dont get it.

Answer

Vojtěch Dohnal picture Vojtěch Dohnal · Jan 29, 2015

Try to use DownloadFile instead of DownloadFileAsync, as you do in Edit 1, like this:

string filename=Path.Combine(TempDirectory, PSFileName);
using (WebClient webClient = new WebClient())
                {
                    // nastaveni ze webClient ma pouzit Windows Authentication
                    webClient.UseDefaultCredentials = true;    
                    // spusteni stahovani
                    webClient.DownloadFile(new Uri("http://czprga2001/Logio_ZelenyKyblik/Export.ashx"), filename);
                }
ExcelToCsv(filename);  //No need to create the event handler if it is not async

From your example it seems that you do not need asynchronous download, so use synchronous download and avoid possible related problems like here.

Also use Path.Combine to combine parts of a path like folder and filename.

There is also a chance that it is locked by something else, use Sysinternals Process Explorer's Find DLL or Handle function to check it.

Use local disk to store downloaded file to prevent problems with network.