views:

7624

answers:

4

I am making a simple program in visual c# 2005 that looks up a stock symbol on Yahoo! Finance, downloads the historical data, and then plots the price history for the specified ticker symbol.

I know the exact URL that I need to acquire the data, and if the user inputs an existing ticker symbol (or at least one with data on Yahoo! Finance) it works perfectly fine. However, I have a run-time error if the user makes up a ticker symbol, as the program tries to pull data from a non-existent web page.

I am using the WebClient class, and using the DownloadString function. I looked through all the other member functions of the WebClient class, but didn't see anything I could use to test a URL.

How can I do this?

+15  A: 

You could issue a "HEAD" request rather than a "GET"?

(edit) - lol! Looks like I've done this before!; changed to wiki to avoid accusations of rep-garnering. So to test a URL without the cost of downloading the content:

// using MyClient from linked post
using(var client = new MyClient()) {
    client.HeadOnly = true;
    // fine, no content downloaded
    string s1 = client.DownloadString("http://google.com");
    // throws 404
    string s2 = client.DownloadString("http://google.com/silly");
}

You would try/catch around the DownloadString to check for errors; no error? It exists...


With C# 2.0 (VS2005):

private bool headOnly;
public bool HeadOnly {
    get {return headOnly;}
    set {headOnly = value;}
}

and

using(WebClient client = new MyClient())
{
    // code as before
}
Marc Gravell
Good idea with switching to wiki in these cases; will keep that in mind for future use...
Fredrik Mörk
*slaps HEAD* - Why did this (the HEAD request) NEVER occur to me before !?!?!?
Cerebrus
FWIW - Not sure if that really solves the problem (other than perhaps different behavior client side) since you are simply changing the HTTP method. The response from the server will depend heavily on how the logic is coded and may not work well for a dynamic service like stock price. For static resources (e.g. images, files etc) HEAD usually works as advertised since it is baked into the server. Many programmers do not explicitly HEAD requests since the focus is normally on POST and GET. YMMV
David Taylor
Sorry for taking so long to pick an answer... I got sidetracked with school and work and kind of forgot about this post.As a sidenote, I couldn't quite get your solution to work because I'm using Visual Studio 2005 which doesn't have the 'var' type. I haven't worked on this project in months, but is there simple fix for that fact? Also when I did try to implement your solution, I remember that it got mad at me for trying to define the HeadOnly property with no code in the 'get' and 'set' definitions. Or maybe I was just doing something wrong. Thanks for the help though!
Daniel Waltrip
A: 

Web servers respond with a HTTP status code indicating the outcome of the request e.g. 200 (sometimes 202) means success, 404 - not found etc (see here). Assuming the server address part of the URL is correct and you are not getting a socket timeout, the exception is most likely telling you the HTTP status code was other than 200. I would suggest checking the class of the exception and seeing if the exception carries the HTTP status code.

IIRC - The call in question throws a WebException or a descendant. Check the class name to see which one and wrap the call in a try block to trap the condition.

David Taylor
Actually, anything in the 200-299 range means success, IIRC
Marc Gravell
Marc, you absolutely are correct. I intentionally avoided get into the "class of error" concept (e.g. 5xx, 4xx, 3xx, 2xx etc) since that opens a whole other can of worms. Even handling the standard codes (200, 302, 404, 500 etc) is much better than ignoring the codes completely.
David Taylor
+2  A: 

If I understand your question correctly, you could use a small method like this to give you the results of your URL test:

WebRequest webRequest = WebRequest.Create(url);  
WebResponse webResponse;
try 
{
  webResponse = webRequest.GetResponse();
}
catch //If exception thrown then couldn't get response from address
{
  return 0;
} 
return 1;

You could wrap the above code in a method and use it to perform validation. I hope this answers the question you were asking.

Calendar Software
Yes, perhaps you can refine the solution by differentiating between different cases (TCP connection failure - host refuses connection, 5xx - Something fatal happened, 404 - Resource not found etc). Have a look at the Status property of WebException ;)
David Taylor
Very good point David! That would give us more detailed feedback so that we could handle the error more astutely.
Calendar Software
Thanks. My point is that there are several layers to this onion, each of which can throw a wrench into the works (.Net Framework, DNS Resolution, TCP Connectivity, target Web Server, target application etc). IMHO a good design should be able to discriminate between the different failure conditions to provide informative feedback and usable diagnostics. Lets also not forget the HTTP has status codes for a reason ;)
David Taylor
this is perfect just what i needed.
Anonymous Type
A: 

Here is another implementation of this solution:

using System.Net;

///
/// Checks the file exists or not.
///
/// The URL of the remote file.
/// True : If the file exits, False if file not exists
private bool RemoteFileExists(string url)
{
    try
    {
        //Creating the HttpWebRequest
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        //Setting the Request method HEAD, you can also use GET too.
        request.Method = "HEAD";
        //Getting the Web Response.
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        //Returns TURE if the Status code == 200
        return (response.StatusCode == HttpStatusCode.OK);
    }
    catch
    {
        //Any exception will returns false.
        return false;
    }
}

From: http://www.dotnetthoughts.net/2009/10/14/how-to-check-remote-file-exists-using-c/

BigJoe714