102

I have the following code:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
request.Credentials = MyCredentialCache;

try
{
    request.GetResponse();
}
catch
{
}

How can I catch a specific 404 error? The WebExceptionStatus.ProtocolError can only detect that an error occurred, but not give the exact code of the error.

For example:

catch (WebException ex)
{
    if (ex.Status != WebExceptionStatus.ProtocolError)
    {
        throw ex;
    }
}

Is just not useful enough... the protocol exception could be 401, 503, 403, anything really.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
JL.
  • 78,954
  • 126
  • 311
  • 459
  • 13
    **NNNOOOOOOOOOOOOO!** Don't catch `System.Exception`, and don't depend on the exception text in your handler! – Aaronaught Jan 28 '10 at 16:09
  • 2
    John Saunders' answer was the most complete. I think people just downvoted him out of spite. – Aaronaught Jan 28 '10 at 16:15
  • 3
    Don't use `throw ex`, you'll generate a new exception with an empty call stack. Just use `throw`. – krbnr Dec 17 '14 at 19:07
  • 2
    I've always found this to be frustrating, myself. An exception shouldn't be thrown if you get a well-formed response, and a protocol error message is definitely well-formed. The class should allow the user to interpret the results and act accordingly. – Jeremy Holovacs Sep 06 '17 at 13:06
  • @JeremyHolovacs exceptions are no longer thrown for things like 404 in newer http clients. "Don't use exceptions for control flow" didn't seem to survive the team who built `WebRequest` – Matt Kocaj Jul 08 '19 at 05:51

10 Answers10

128
try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    {
        using (var responseStream = response.GetResponseStream())
        {
            // Process the stream
        }
    }
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError &&
        ex.Response != null)
    {
        var resp = (HttpWebResponse) ex.Response;
        if (resp.StatusCode == HttpStatusCode.NotFound)
        {
            // Do something
        }
        else
        {
            // Do something else
        }
    }
    else
    {
        // Do something else
    }
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
123

Use the HttpStatusCode Enumeration, specifically HttpStatusCode.NotFound

Something like:

HttpWebResponse errorResponse = we.Response as HttpWebResponse;
if (errorResponse.StatusCode == HttpStatusCode.NotFound) {
  //
}

Where
we is a WebException.

Jay Riggs
  • 53,046
  • 9
  • 139
  • 151
  • can I get the NUMBER out somehow from the objects without making my own lookup list? I would like to have something like: int httpresponsecode = HttpStatusCode.ToInt() or similar so I get 404 – BerggreenDK Apr 12 '11 at 14:42
  • 2
    @BerggreenDK you should be able to just do int httpresonsecode = **(int)** HttpStatusCode.NotFound – Trev Mar 14 '12 at 14:30
  • 8
    -1 Partial explanation of my ancient downvote: code throws NullReferenceException if, for some reason, `we.Response` is not `HttpWebResponse`. If the code wishes to assume that it will always have that type, then it should simply cast: `HttpWebResponse errorResponse = (HttpWebResponse)we.Response;`. This will throw an explicit `InvalidCastException` if the impossible happens, instead of a mysterious `NullReferenceException`. – John Saunders Apr 21 '14 at 18:17
  • I get `An object reference is required for the non-static field, method, or property 'WebException.Response'` using this code. – Jamie Jan 09 '18 at 15:17
32

In C# 6 you can use exception filters.

try
{
    var request = WebRequest.Create(uri);
    using (var response = request.GetResponse())
    using (var responseStream = response.GetResponseStream())
    {
        // Process the stream
    }
}
catch(WebException ex) when ((ex.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
{
    // handle 404 exceptions
}
catch (WebException ex)
{
    // handle other web exceptions
}
craftworkgames
  • 9,437
  • 4
  • 41
  • 52
  • A very cool feature that I've been overlooking! I kept seeking methods to catch only 401 while letting others pass through to the general exception handler. This is the way to go! – Lionet Chen Feb 08 '17 at 03:55
12

I haven't tested this, but it should work

try
{
    // TODO: Make request.
}
catch (WebException ex)
{
    if (ex.Status == WebExceptionStatus.ProtocolError) {
        HttpWebResponse resp = ex.Response as HttpWebResponse;
        if (resp != null && resp.StatusCode == HttpStatusCode.NotFound)
        {
            // TODO: Handle 404 error.
        }
        else
            throw;
    }
    else
        throw;
}
MiffTheFox
  • 21,302
  • 14
  • 69
  • 94
  • @John Saunders - I was adapting the OP's code, not optimizing it. – MiffTheFox Jan 27 '10 at 19:24
  • @John - And maybe I was only expecting them to copy/paste the `catch` block, seeing as I had the exact same code in the try as the OP. You should really be downvoaing this question altogether because of the OP's code then. – MiffTheFox Jan 28 '10 at 15:58
  • 1
    @John we forget here is sample code. This is case it is another way to 404, not how to use GetResponse. -1 seems a little harsh. +1 to Miff for answering the question. – David Basarab Jan 28 '10 at 17:38
  • @John I think it is good you point it out in a comment. The way I look at down voting is if the code given doesn't solve the problem. Thank you for removing the down vote. – David Basarab Jan 28 '10 at 18:45
  • @John - Fine, I got rid of everything but the catch, happy now? – MiffTheFox Jan 28 '10 at 21:41
  • @MiffTheFox: in case you didn't notice, yes, I was happy and removed the downvote and my comments. You might want to remove your comments as well. – John Saunders Jan 25 '14 at 22:04
4

I think if you catch a WebException there is some information in there that you can use to determine if it was a 404. That's the only way I know of at the moment...I'd be interested in knowing any others...

catch(WebException e) {
    if(e.Status == WebExceptionStatus.ProtocolError) {
        var statusCode = (HttpWebResponse)e.Response).StatusCode);
        var description = (HttpWebResponse)e.Response).StatusDescription);
    }
}
mezoid
  • 28,090
  • 37
  • 107
  • 148
2

Check out this snipit. The GetResponse will throw a WebRequestException. Catch that and you can get the status code from the response.

try {
   // Create a web request for an invalid site. Substitute the "invalid site" strong in the Create call with a invalid name.
     HttpWebRequest myHttpWebRequest = (HttpWebRequest) WebRequest.Create("invalid site");

    // Get the associated response for the above request.
     HttpWebResponse myHttpWebResponse = (HttpWebResponse) myHttpWebRequest.GetResponse();
    myHttpWebResponse.Close();
}
catch(WebException e) {
    Console.WriteLine("This program is expected to throw WebException on successful run."+
                        "\n\nException Message :" + e.Message);
    if(e.Status == WebExceptionStatus.ProtocolError) {
        Console.WriteLine("Status Code : {0}", ((HttpWebResponse)e.Response).StatusCode);
        Console.WriteLine("Status Description : {0}", ((HttpWebResponse)e.Response).StatusDescription);
    }
}
catch(Exception e) {
    Console.WriteLine(e.Message);
}

this came from http://msdn.microsoft.com/en-us/library/system.net.webexception.status.aspx

Jonathan S.
  • 541
  • 1
  • 3
  • 13
2

See at MSDN about status of the response:

...
catch(WebException e) {
  Console.WriteLine("The following error occured : {0}",e.Status);  
}
...
Dror
  • 7,255
  • 3
  • 38
  • 44
  • 2
    @John Saunders - I'll be more than happy to pass it along to MSDN (where I copied the sample from...). The purpose of this code is to show the usage of StatusCode, not be as efficient as possible. – Dror Jan 28 '10 at 09:04
  • 2
    @John Saunders - I left only the part I wanted to show, Just for you :-) – Dror Jan 28 '10 at 16:09
2

Catch the proper exception type WebException:

try
{
    var request = (HttpWebRequest) WebRequest.Create(String.Format("http://www.gravatar.com/avatar/{0}?d=404", hashe));

    using(var response = (HttpWebResponse)request.GetResponse())
        Response.Write("has avatar");
}
catch(WebException e) 
{
  if(e.Response.StatusCode == 404) 
    Response.Write("No avatar");
}
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • @John Saunders I don't debate you there, but that wasn't the question, he asked the best way to capture a 404. My changes to his code were limited to answering the question, to make the change as simple and obvious as possible. – Nick Craver Jan 27 '10 at 18:46
  • @John Saunders: Fixed, I suppose "if this is the most efficient" makes it apply to the question. – Nick Craver Jan 27 '10 at 18:59
  • Just had to cast the `e.Response` as `HttpWebResponse` before gaining access to the `StatusCode`. – user692942 Oct 26 '18 at 11:46
2

For VB.NET folks browsing this, I believe we can catch the exception only if it truly is a 404. Something like:

Try
    httpWebrequest.GetResponse()
Catch we As WebException When we.Response IsNot Nothing _
                              AndAlso TypeOf we.Response Is HttpWebResponse _
                              AndAlso (DirectCast(we.Response, HttpWebResponse).StatusCode = HttpStatusCode.NotFound)

    ' ...

End Try
unnknown
  • 1,715
  • 2
  • 19
  • 37
2

when POST or GET data to the server using WebRequest class then the type of exception would be WebException.Below is the code for file not found exception

//Create a web request with the specified URL
string path = @"http://localhost/test.xml1";
WebRequest myWebRequest = WebRequest.Create(path);

//Senda a web request and wait for response.
try
{
  WebResponse objwebResponse = myWebRequest.GetResponse();
  Stream stream= objwebResponse.GetResponseStream();
}
catch (WebException ex) {
  if (((HttpWebResponse)(ex.Response)).StatusCode == HttpStatusCode.NotFound) {
    throw new FileNotFoundException(ex.Message);
  }
}
xxx
  • 1,153
  • 1
  • 11
  • 23
Sheo Dayal Singh
  • 1,591
  • 19
  • 11