|
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:
- You want to make sure your application remains
performant while the network request is being made.
- 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.
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.
|