Reputation: 1050
I have a simple C# Windows UAP project that uses a HttpClient
to call a PHP script on a web server. The script returns an XML document that contains some GUIDs (*.xml
files with the extension omitted, leaving a GUID). My app then uses that data. If I make a change on the server, coincidently causing the PHP script to return different data, my app still uses the old data (to be exact, it does this until the app is restarted). If a call the script using a browser, the data appears how I expect it to, but the app doesn't do what it should with the data. It almost seems like the first response is being cached.
Here's an example:
Say I start with one file in the folder where my PHP script finds all *.xml files (eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xml
in this case).
The script should and does return:
<?xml version="1.0"?>
<eventlist>
<id>eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
</eventlist>
When I run the app, its response is the same.
So far, all is working as it should.
However, say I add a new XML file in the folder (now eee8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xml
and eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62.xml
). The script returns just like I expect it to:
<?xml version="1.0"?>
<eventlist>
<id>eee8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
<id>eef8401a-b5cd-4da7-ad36-0fb7a8fa6c62</id>
</eventlist>
The app's response this time is still the previous one (with only one id
element).
This persists until the app restarts. After that, it works like it should--until I make another change in the folder.
Here's my PHP script:
<?php
header('Content-type: text/xml');
$handler = opendir('C:\path\to\folder\\');
$ids = '';
while (($file = readdir($handler)) !== FALSE) {
if (strpos($file, '.xml') !== FALSE) {
$ids .= '<id>'.str_replace('.xml', '', $file).'</id>';
}
}
closedir($handler);
exit('<eventlist>'.$ids.'</eventlist>');
?>
And my app's C# code:
public static async Task<string> ContactServer(ApiMethod m, IProgress<double[]> prog, params KeyValuePair<string, string>[] args) {
using (var client = new HttpClient()) {
var path = m.ToString().ToLower() + "/"; // in this case, is 'list/'.
//...
// other stuff, omitted for simplicity
//...
var fullUrl = "http://example.com/path/to/api/" + path; // in this case, is 'http://example.com/path/to/api/list/'.
var d = await client.GetAsync(new Uri(fullUrl));
var data = await d.Content.ReadAsStringAsync();
Debug.WriteLine(data);
return data;
}
}
Again, my PHP script works fine, but my app gets a different response than I do when I run the script in my browser manually.
Why is this happening?
Upvotes: 3
Views: 110
Reputation: 8901
Windows Runtime which provides the HTTPClient has a very aggressive webcaching strategy to save user's bandwidth. Unless your server explicitly sets a cache duration header, it will return all** requests with the same Uri directly from the cache without even contacting your server.
You can turn off this behaviour by:
Setting a cache duration header (cache-control: no-cache, etc.).
var request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (request.Headers == null)
request.Headers = new WebHeaderCollection();
request.Headers.Add("Cache-Control", "no-cache");
Adding a random number to your requests query string.
string uri = "http://host.com/path?cache=" + Guid.NewGuid().ToString();
Or, as CodeCaster suggested, you could also avoid the caching by using the If-Modified-Since
header
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
if (request.Headers == null)
request.Headers = new WebHeaderCollection();
// Make sure that you format time string according RFC.
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString("r");
or you can add to every request the client makes with
httpClient.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow.ToString("r");
Using Windows.Web.Http
you could also use
var httpFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
httpFilter.CacheControl.ReadBehavior =
Windows.Web.Http.Filters.HttpCacheReadBehavior.MostRecent;
var httpClient = new Windows.Web.Http.HttpClient(httpFilter);
** I have said all requests, but I don't know if that is strictly correct, I will take a look and check and update here, though CodeCaster has suggested GET
and HEAD
only; I have certainly seen on GET
, unsure about others off the top of my head
Upvotes: 2