24

I have a program I'm writing that downloads to files. The second file is not neccassary and is only some times included. When the second file is not included it will return an HTTP 404 error.

Now, the problem is that when this error is returned it ends the whole program. What I want is to continue the program and ignore the HTTP error. So, my question is how do I catch an HTTP 404 error from a WebClient.DownloadFile request?

This is the code currently used::

WebClient downloader = new WebClient();
foreach (string[] i in textList)
{
    String[] fileInfo = i;
    string videoName = fileInfo[0];
    string videoDesc = fileInfo[1];
    string videoAddress = fileInfo[2];
    string imgAddress = fileInfo[3];
    string source = fileInfo[5];
    string folder = folderBuilder(path, videoName);
    string infoFile = folder + '\\' + removeFileType(retrieveFileName(videoAddress)) + @".txt";
    string videoPath = folder + '\\' + retrieveFileName(videoAddress);
    string imgPath = folder + '\\' + retrieveFileName(imgAddress);
    System.IO.Directory.CreateDirectory(folder);
    buildInfo(videoName, videoDesc, source, infoFile);
    textBox1.Text = textBox1.Text + @"begining download of files for" + videoName;
    downloader.DownloadFile(videoAddress, videoPath);
    textBox1.Text = textBox1.Text + @"Complete video for" + videoName;
    downloader.DownloadFile(imgAddress, imgPath);
    textBox1.Text = textBox1.Text + @"Complete img for" + videoName;
}
Amar Palsapure
  • 9,590
  • 1
  • 27
  • 46
Alex Gatti
  • 295
  • 1
  • 2
  • 8

9 Answers9

32

If you specifically want to catch error 404:

using (var client = new WebClient())
{
  try
  {
    client.DownloadFile(url, destination);
  }
  catch (WebException wex)
  {
    if (((HttpWebResponse) wex.Response).StatusCode == HttpStatusCode.NotFound)
    {
      // error 404, do what you need to do
    }
  }
}

Or, using C# 7 or later:

using (var client = new WebClient())
{
  try
  {
    client.DownloadFile(url, destination);
  }
  catch (WebException ex) when
        (ex.Response is HttpWebResponse wr && wr.StatusCode == HttpStatusCode.NotFound)
  {      
    // error 404, do what you need to do
  }
}
Joe Albahari
  • 30,118
  • 7
  • 80
  • 91
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
  • 4
    This should've been the accepted answer. Getting an actual `HttpWebResponse.StatusCode` `enum` value is much better imo than looking for code in `string` message :-) – Skipper Aug 23 '18 at 11:39
  • wex.Response is null... Don't write answers without testing it first... – RaZzLe Dec 21 '20 at 21:11
12

WebClient will throw a WebException for all 4xx and 5xx responses.

try {
    downloader.DownloadFile(videoAddress, videoPath);
}
catch (WebException ex) {
    // handle it here
}
Community
  • 1
  • 1
John Sheehan
  • 77,456
  • 30
  • 160
  • 194
7

Put the try catch inside your foreach Loop.

 foreach (string[] i in textList)
 {
    try
    {
        String[] fileInfo = i;
        string videoName = fileInfo[0];
        string videoDesc = fileInfo[1];
        string videoAddress = fileInfo[2];
        string imgAddress = fileInfo[3];
        string source = fileInfo[5];
        string folder = folderBuilder(path, videoName);
        string infoFile = folder + '\\' + removeFileType(retrieveFileName(videoAddress)) + @".txt";
        string videoPath = folder + '\\' + retrieveFileName(videoAddress);
        string imgPath = folder + '\\' + retrieveFileName(imgAddress);
        System.IO.Directory.CreateDirectory(folder);
        buildInfo(videoName, videoDesc, source, infoFile);
        textBox1.Text = textBox1.Text + @"begining download of files for" + videoName;
        if(Download(videoAddress, videoPath) == false)
        {
           //Download failed. Do what you want to do.
        }
        textBox1.Text = textBox1.Text + @"Complete video for" + videoName;
        if(Download(imgAddress, imgPath)== false)
        {
           //Download failed. Do what you want to do.
        }
        textBox1.Text = textBox1.Text + @"Complete img for" + videoName;
    }
    catch(Exception ex)
    {
        //Error like IO Exceptions, Security Errors can be handle here. You can log it if you want.
    }
 }

Private function to Download file

 private bool Download(string url, string destination)
 {
     try
     {
         WebClient downloader = new WebClient();
         downloader.DownloadFile(url, destination);
         return true;
     }
     catch(WebException webEx)
     {
        //Check (HttpWebResponse)webEx.Response).StatusCode
        // Or
        //Check for webEx.Status
     }
     return false;
 }

You can check the WebException for status. Depending upon the error code you can continue or break.

Read More @ MSDN

Suggestion

Hope this works for you.

Amar Palsapure
  • 9,590
  • 1
  • 27
  • 46
1

you can try this code to get HTTP status code from WebException or OpenReadCompletedEventArgs.Error:

HttpStatusCode GetHttpStatusCode(System.Exception err)
{
    if (err is WebException)
    {
        WebException we = (WebException)err;
        if (we.Response is HttpWebResponse)
        {
            HttpWebResponse response = (HttpWebResponse)we.Response;
            return response.StatusCode;
        }
    }
    return 0;
}
Sergey
  • 1,552
  • 20
  • 18
0

Important: On a 404 failure DownloadFileTaskAsync will throw an exception but will ALSO create an empty file. This can be confusing to say the least!

Took me way too long to realize that this code creates an empty file in addition to throwing an exception:

await webClient.DownloadFileTaskAsync(new Uri("http://example.com/fake.jpg"), filename);

Instead I switched to this (DownloadDataTaskAsync instead of File):

 var data = await webClient.DownloadDataTaskAsync(new Uri("http://example.com/fake.jpg"));
 File.WriteAllBytes(filename, data);

*I'm not sure about 500 behavior, but for sure a 404 does this.

Community
  • 1
  • 1
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0

I would use sth like this.

    public void Test()
    {
        try
        {
            WebClient webClient = new WebClient();
            webClient.DownloadString("");
        }
        catch (WebException webException)
        {
            if (int.TryParse(
                Regex.Match(webException.Message, @"(?<=error:\s\()\d+(?=\))", RegexOptions.Multiline).Value,
                out var result))
            {
                switch (result)
                {
                    case 404:
                        Console.WriteLine("Error 404");
                        break;
                    case 500:
                        Console.WriteLine("Error 500");
                        break;
                }
            }
        }
    }
Andie2302
  • 4,825
  • 4
  • 24
  • 43
0

Use a try catch WebException in your code and examine the Exception message - it will contain the http StatusCode.

You can clear the Exception and continue.

Chad
  • 1,531
  • 3
  • 20
  • 46
Laird Streak
  • 397
  • 5
  • 8
  • 1
    How do I clear the exception and make the program continue once I catch the exception? Sorry if this seems newbish but I am a newb. – Alex Gatti Jan 23 '12 at 08:21
  • try { downloader.DownloadFile(videoAddress, videoPath); catch (WebException ex) { // handle it here // by leaving the code clear here the exception is not handled and the process can continue :) } – Laird Streak Jan 23 '12 at 08:28
  • 1
    This doesn't seem to work. If the file isn't there, the API is downloading the HTML 404 error page as the file. – Chizl Apr 07 '14 at 17:26
0

Use a try{} catch{} block with the WebException inside your loop ! Dunno what IDE u are using but with Visual Studio u can get a lot of information about the exception :)

Guillaume Slashy
  • 3,554
  • 8
  • 43
  • 68
0

As other write, as try-catch would suffice.

Another tip is to use HTTP HEAD to check if there is anything there (it's lighter than doing a full HTTP GET):

var url = "url to check";
var req = HttpWebRequest.Create(url);
req.Method = "HEAD"; //this is what makes it a "HEAD" request
WebResponse res = null;
try
{
    res = req.GetResponse();
    res.Close();
    return true;
}
catch
{
    return false;
}
finally
{
    if (res != null)
        res.Close();
}
Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
Holger
  • 2,243
  • 17
  • 19