I hit an problem doing some dev on Windows Phone 7 several weeks back and have since helped a couple people out in the old windows phone 7 forum and LinkedIn Windows Phone 7 user group with the same thing. This issue, is in fact, not an issue – it is more of a lack of knowledge that the HttpWebRequest and WebClient cache responses for your web request. Let me tell you that client side caching is a good thing that will save you bandwidth and also speed up the percieved user experience when requesting the same resource. So probably best to get straight to where problems can be faced.
If you are performing a HttpWebRequest to a uri like so:
string someUri = "http://someservice/service/GetContent/userid/"; HttpWebRequest request = HttpWebRequest.CreateHttp(someUri); request.Accept = "application/json"; request.BeginGetResponse(OnGetSomeontentCallback, new GetSomeContentState(request, onResultAction));
Now lets pretend your service implementation has some smarts around what the user has seen historicaly and returns a different image each time you request the same uri. You will find on your second call to the service that the same image is displayed in your app as the first call and then you might scratch your head *scratch*, check your service logic – all looks ok, set a breakpoint in your service and bang – the breakpoint is not being hit in the service on the second call and suddently is becomes clear the HttpWebRequest (and WebClient) for that matter will cache the response for that uri.
So your faced with the following question – Should I change my service interface or change/remove the client side caching for this service operation?. Well the answer is application specific and will fall into two categories:
1. Your client application knows what resource should be next
- In this case you should alter your service interface to accept the Id of the item this way the result will be cached only for each specific item.
2. Your client has no idea what should be next as the server figures it out
- In this scenario i have identified 3 options – initialy i though you would be able to change the cache to expire or not cache on the HttpWebRequest instance but this is not in fact possible so you have to look at the uri and/or serverside. Here are 3 options:
Option 1: Add a random Query String to the end of your URI (think Guid.NewGuid()) this will avoid caching on the client as the Query String will be different each time
Option 2. Specify no cache in the OutgoingResponse header within your WCF service operation:
public ResultABC GetContent(string abc) { ... WebOperationContext.Current.OutgoingResponse.Headers.Add("Cache-Control", "no-cache"); //This line ... return ...; }
Option 3. markup your service operation with the AspNetCacheProfile attribute:
[AspNetCacheProfile("GetContent")] public ResultABC GetContent(string abc) { ... ... return ...; }
update your web.config
<system.web> <caching> <outputCache enableOutputCache="true" /> <outputCacheSettings> <outputCacheProfiles > <add name="GetContent" duration="0" noStore="true" location="Client" varyByParam="" enabled="true"/> </outputCacheProfiles> </outputCacheSettings> </caching> ... </system.web>
What did I choose:
Well all methods work to avoid the particular scenario given. But in my case, the client application never knows what is next so I was forced to stop the client side cachingso the one I opted for was Option 3 as externalising this configuration means you can change at any later time without needing to rebuild and deploy your service.
If my client did know what the user was requesting then I would have gone for passing the ID in the uri to ensure that it is unique per each resource and that each resource would be cached on its unique uri. Note here it is important for the ID to be passed on the URI it appears the URI forms the key for the cache i did see one example where the user was passing the ID in the Header collection e.g wc.Header[“ID”] = id; and this was exhibiting the same problem. Moving the ID to the URI solves the problem.
Hope this has been helpful,
Nick