Checking if a Remote (HTTP) File Exists
by kirupa |  11 September 2010

If you are going to be performing any action on a file, you want to make sure the file exists first. This is easier for files stored locally on your machine where you can simply do a File.Exists call and...call it a day.

Things are a little bit more tricky when you try to check if a remote file such as something on a HTTP server exists though. Given the nature of requests traveling over a network, there are two things to keep in mind that make performing this check non-trivial:

  1. You want to make sure your application remains performant while the network request is being made.
  2. You do not want to download the entire remote file when checking if it exists.

Given those two requirements, you have to do a little more work than just using a simle File.Exists call. Instead, you have to construct a web request yourself and listen for the appropriate response to verify that the remote file exists. In this article, since it is more of a deconstruction as opposed to a tutorial, I will provide you the code for doing both of those pieces:

Download and extract the above files to a location on disk. Make sure you have everything you need to get started with Windows Phone development, open the solution in Visual Studio, and look into MainPage.xaml.cs.

Looking at the Code
Now that you have an idea of what we need to do, let's go ahead and look at the code. The code for constructing a web request and listening for whether a file exists or not is:

public MainPage()
{
InitializeComponent();
 
Uri filePath = new Uri("http://www.kirupa.com/blah/");
 
HttpWebRequest fileRequest = HttpWebRequest.CreateHttp(filePath);
fileRequest.Method = "HEAD";
 
fileRequest.BeginGetResponse(new AsyncCallback(WebRequestCallBack), fileRequest);
}
 
void WebRequestCallBack(IAsyncResult result)
{
HttpWebRequest resultInfo = (HttpWebRequest) resultInfo.AsyncState;
HttpWebResponse response;
 
try
{
response = (HttpWebResponse)request.EndGetResponse(result);
 
string statusCode = response.StatusCode.ToString();
}
catch (WebException e)
{
string statusCode = e.Message;
}
}

You can use the code as-is in your Windows Phone projects. Some of the classes used live in the System.Net namespace, so make sure your code file gives a shoutout at the top to the System.Net namespace:

using System.Net;

That's all there is to it. To help you make the most of the code and so that you can use it better in our own project, let's go through each section in greater detail starting at the top:

Uri filePath = new Uri("http://www.kirupa.com/blah/moo.zip");
 
HttpWebRequest fileRequest = HttpWebRequest.CreateHttp(filePath);
fileRequest.Method = "HEAD";

In the first line, I create my Uri object called filePath that specifies the URL to the file I am interested in checking. This is pretty straightforward.

Things get interesting with the second line. Here, I construct my HttpWebRequest object called fileRequest. Notice that I pass in the filePath Uri object I created earlier when initializing this request.

The last step in actually making the request is specifying what HTTP method to use as part of my request:

fileRequest.Method = "HEAD";

The methods you can commonly use are HEAD, GET, PUT, POST, and DELETE. I am using the HEAD method because I just want to know more about this file without actually downloading the file.

Once the request has been created, it's time to send it off:

fileRequest.BeginGetResponse(new AsyncCallback(WebRequestCallBack), fileRequest);

The BeginGetResponse method is responsible for sending a request asynchronously to a URI that you specify. This means that your UI will remain responsive while the request is sent.

This method takes one argument, and that argument is an asynchronous callback function:

fileRequest.BeginGetResponse(new AsyncCallback(WebRequestCallBack), fileRequest);

I create a new AsyncCallback object that defines a handler for the callback and takes our fileRequest HttpWebRequest object as its argument. When a response is heard back, the WebRequestCallBack method will get fired. Let's look at that method next.


Right now, our web requesst has been made, and the response is handled by the WebRequestCallBack method:

void WebRequestCallBack(IAsyncResult result)
{
HttpWebRequest resultInfo = (HttpWebRequest)result.AsyncState;
HttpWebResponse response;
 
try
{
response = (HttpWebResponse) resultInfo.EndGetResponse(result);
 
string statusCode = response.StatusCode.ToString();
}
catch (WebException e)
{
string statusCode = e.Message;
}
}

This method brings with it one argument, and that is a result object whose type is IAsyncResult. This result object contains a response back from the web server that you sent a request to. In the first two lines, I basically unwrap the response into a form that we can make sense of:

HttpWebRequest resultInfo = (HttpWebRequest)result.AsyncState;
HttpWebResponse response;

The first thing I do is get our result information wrapped back into the original HttpWebRequest format through a variable called resultInfo. As you will see shortly, I am doing this so that I can formally conclude my web request.

Finally, to help parse the response from the request, I declare a HttpWebResponse object very cleverly called, response!

The final piece of the puzzle lies in the next few lines where I dig into the response and get the answer that you have been searching your entire life for, "Does that file exist on the server?"

These lines are:

try
{
response = (HttpWebResponse) resultInfo.EndGetResponse(result);
 
string statusCode = response.StatusCode.ToString();
}
catch (WebException e)
{
string statusCode = e.Message;
}

Because this a very exception-happy set of code, I wrap everything into a try/catch statement. The try part deals with handling the case where the file is found:

response = (HttpWebResponse) resultInfo.EndGetResponse(result);
 
string statusCode = response.StatusCode.ToString();

Notice that I first take our resultInfo object and call the EndGetResponse method to end the web request started off earlier by our BeginGetResponse. The EndGetResponse method takes an IAsyncResult object as its argument, and it returns data back in the form of a WebResponse. Fortunately our result and response objects have both bases of that covered!

Now, all that is left is to read the HTTP status code that was returned:

string statusCode = response.StatusCode.ToString();

The StatusCode property returns the appropriate HttpStatusCode value which I bludgeon by just ToString-ing it into something I can read. You can handle this more appropriately if you feel the need to of course.

In the case that a response was not successful such as the file not being found, the code in the catch part will run:

catch (WebException e)
{
string statusCode = e.Message;
}

I constrain the exception by only listening for a WebException, and I all I am doing in the body of the catch statement is just seeing what the message returned by the exception is.


 

 




SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.