No cache with HttpClient in Windows Phone 8
Asked Answered
R

5

8

I've read that in order to disable caching while using get and post methods in HttpClient, I need to use a WebRequestHandler as my HttpClient's HttpClientHandler, and change its cache policy. However, WebRequestHandler is not within System.Net.Http.dll, but rather in System.Net.Http.WebRequest.dll, so I tried to add the .dll to the project as a reference. I got an error message:

Microsoft Visual Studio

A reference to a higher version or incompatible assembly cannot be added to the project.

Again, after a little search, I concluded that the .dll file was blocked because it was downloaded from another source. To unblock it, I went on trying the solution here. However, it didn't work either and I'm still getting the same error when I try to add the .dll file as a reference.

All I want to do is disable caching using my HttpClient, am I doing anything wrong here? I'm open to any type of advice or help.

My system is Windows 8.1 and I'm using Visual Studio 2013. The project I'm working on is a Windows Phone 8 application. The directory of .dll I'm trying to reference is "C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Net.Http.WebRequest.dll". Thank you in advance.

Ripuarian answered 15/1, 2014 at 10:5 Comment(1)
How about setting ifModifiedSince header to current time in your request header..Edmonson
S
27

It's not possible to reference regular .NET assemblies in a Windows Phone 8 project. You can only use the .NET API for Windows Phone. This is a subset of regular .NET. See http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207211%28v=vs.105%29.aspx for more info.

The default caching of HttpClient (and HttpWebRequest) can be worked around by appending a value to the query string. For example, a guid.

string uri = "http://host/path?cache=" + Guid.NewGuid().ToString();

A better solution, like pointed out in the comment above, is to set the "If-Modified-Since" header. HttpWebRequest has it built in:

HttpWebRequest request = HttpWebRequest.CreateHttp(url);
if (request.Headers == null)
    request.Headers = new WebHeaderCollection();
// Make sure that you format time string according RFC.
// Otherwise setting header value will give ArgumentException for culture like 'ti-ER'
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString("r"); 

But you could add the header manually using an HttpClient I guess.

Streamlet answered 21/1, 2014 at 10:51 Comment(4)
Thanks, adding the IfModifiedSince header seems to be working for now.Ripuarian
Note that you should use DateTime.UtcNow.ToString("r"); so that the timestamp is formatted correctly as per the RFC.Congregate
You guy save my life, I banging my head againt the wall since so long right now! Worst thing is this auto caching is processed only on WP App, not on Universal App, wtf?!Terceira
This solution may be a hack specific to Windows Phone. I tried using this in a Xamarin app (also for Windows Phone) and it caused the server to always return a 304 Not Modified response, which makes sense since If-Modified-Since "right now" is seldom true if there is any sort of caching on the server. What ended up working for me was client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue() { NoCache = true };Flutter
P
8

If using Windows.Web.Http.HttpClient, the clean way to fix this issue from the client side is:

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

This way, you avoid filling the app's cache with temp files when using random query strings. Each response is stored in the cache.

Of course, it is always recommended to fix the issue from the server side. Add the following header, and you won't need to worry about cache on each client:

Cache-Control: no-cache

Full response:

HTTP/1.1 200 OK
Content-Length: 31
Content-Type: text/plain; charset=UTF-8
Cache-Control: no-cache

...
Partheniaparthenocarpy answered 1/2, 2015 at 19:7 Comment(0)
W
7

I found 3 ways

  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

string uri = "http://host.com/path?cache=" + Guid.NewGuid().ToString();

  1. Specify no cache in the OutgoingResponse header within your WCF service operation:
var __request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (__request.Headers == null)
    __request.Headers = new WebHeaderCollection();
__request.Headers.Add("Cache-Control", "no-cache");
  1. markup your service operation with the AspNetCacheProfile attribute:
[AspNetCacheProfile("GetContent")]  
public ResultABC GetContent(string abc)  
{  
  __request = (HttpWebRequest)WebRequest.Create(abc);
  return __request;  
}

And 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>
Workman answered 3/10, 2014 at 11:57 Comment(1)
Option 2 is the correct way to avoid retrieving results from the client side cache.Chateau
K
5

I wrote a HttpMessageHandler based on the solution above:

public class BypassCacheHttpRequestHandler : HttpClientHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Headers.IfModifiedSince == null)
            request.Headers.IfModifiedSince = new DateTimeOffset(DateTime.Now);
        return base.SendAsync(request, cancellationToken);
    }
}

Use new HttpClient(new BypassCacheHttpRequestHandler(), true); to initialize your HttpClient then you can always bypass cache.

Kappenne answered 1/9, 2014 at 22:25 Comment(1)
Or you could just set the HttpClient.DefaultRequestHeader. Also, it is more correct to do httpClient.DefaultRequestHeader.CacheControl = new CacheControlHeaderValue() {NoCache=true};Chateau
S
5

This for windows phone to get fresh data instead of catching data

Using(HttpClient httpClient = new HttpClient())
{
    httpClient.DefaultRequestHeaders.IfModifiedSince = DateTimeOffset.Now;
    //your code goes here`enter code here`
}

another alternative is set

Response.Cache.SetCacheability(HttpCacheability.NoCache);

in server page Page_Load if u get data from aspx page

Soul answered 20/8, 2015 at 8:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.