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

  Have questions? Discuss this Windows Phone tutorial with others on the forums.

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 simple 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, below you will find a project containing the code for both creating and sending the web request and listening for the response:

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 in MainPage.xaml.cs.

Looking at the Code
MainPage.xaml.cs contains the sample code that does the bare minimum for checking if a remote file exists:

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;
}
}

For the rest of this page, let's go through and understand what all of the above code does so that you can easily modify and port it for your own needs.

The first thing we do is adding a using statement for the System.Net namespace:

using System.Net;

The reason we do that is because a handful of the classes we will be using live in the System.Net namespace.


The next set of code is where things begin to get interesting:

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. In the Uri constructor, I specify the URL to the file I am interested in checking whether it exists or not.

The second line is where the Uri object becomes more useful! 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 reason is that I am using the CreateHttp method from the HttpWebRequest class to tell my request what location to send the request to, and the filePath Uri object I created earlier contains that information.

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 URL that you specify. What asynchronous brings to the table is that your UI will remain responsive even when a part of your application is dealing with sending the request and waiting for a response.

The BeginGetResponse 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.

And with that, you are done!


If you have a question about this or any other topic, the easiest thing is to drop by our forums where a bunch of the friendliest people you'll ever run into will be happy to help you out!

THE KIRUPA NEWSLETTER

Get cool tips, tricks, selfies, and more...personally hand-delivered to your inbox!

( View past issues for an idea of what you've been missing out on all this time! )

WHAT DO YOU THINK?

blog comments powered by Disqus




SUPPORTERS:

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