在Windows Phone 8中使用HttpClient时没有缓存

8
我读到了在使用get和post方法时禁用缓存的方法是使用WebRequestHandler作为HttpClientHttpClientHandler,并更改其缓存策略。然而,WebRequestHandler不在System.Net.Http.dll中,而是在System.Net.Http.WebRequest.dll中,因此我尝试将.dll文件作为引用添加到项目中。但是,我收到了一个错误消息:
“Microsoft Visual Studio”
“无法向项目添加对版本较高或不兼容的程序集的引用。”
再次经过一番搜索后,我得出结论:由于从另一个来源下载了该.dll文件,因此该文件被阻止。为了解除阻止,我尝试了这里的解决方案。但是,它也没有起作用。当我尝试将.dll文件作为引用添加时,仍然会收到相同的错误。
我只想禁用使用HttpClient的缓存,我做错了什么吗?我愿意接受任何类型的建议或帮助。

我的系统是Windows 8.1,我正在使用Visual Studio 2013。我正在开发一个Windows Phone 8应用程序。我尝试引用的.dll文件目录是"C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Net.Http.WebRequest.dll"。谢谢。


1
在您的请求头中将ifModifiedSince标头设置为当前时间如何? - Prasanna Aarthi
5个回答

27

在Windows Phone 8项目中无法引用常规的.NET程序集,只能使用适用于Windows Phone的.NET API。这是常规.NET的子集。有关更多信息,请参见http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207211%28v=vs.105%29.aspx

可以通过将一个值附加到查询字符串来解决HttpClient(和HttpWebRequest)的默认缓存问题,例如guid。

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

正如上面评论所指出的,更好的解决方案是设置"If-Modified-Since"头部。HttpWebRequest已经内置了它:

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

但我想你可以使用 HttpClient 手动添加标头。


谢谢,目前添加IfModifiedSince头似乎有效。 - halileohalilei
2
请注意使用 DateTime.UtcNow.ToString("r"); 以便时间戳按照 RFC 格式正确格式化。 - Matt Lacey
你们救了我的命,我现在已经撞墙很久了!最糟糕的是这个自动缓存只在 WP 应用程序上处理,而不在通用应用程序上,真是什么鬼?! - Julien Leray
这个解决方案可能是针对Windows Phone特定的一个hack。我尝试在Xamarin应用程序中使用它(也是为Windows Phone),但它会导致服务器始终返回304未修改响应,这是有道理的,因为如果服务器上有任何缓存,If-Modified-Since“现在”很少是真实的。最后让我成功的是client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue() { NoCache = true }; - Rich

8
如果使用的是 Windows.Web.Http.HttpClient,客户端解决此问题的 正确 方法如下:
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);

这样做可以避免在使用随机查询字符串时将临时文件填满应用程序缓存。每个响应都存储在缓存中。
当然,建议从服务器端解决问题。添加以下标头,您就不必担心每个客户端的缓存:
Cache-Control: no-cache

完整响应:

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

...

7

我找到了三种方法:

  1. 在URI末尾添加一个随机的查询字符串(类似Guid.NewGuid()),这将避免客户端缓存,因为每次查询字符串都会不同。

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

  1. 在WCF服务操作中指定出站响应头中的无缓存。
var __request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (__request.Headers == null)
    __request.Headers = new WebHeaderCollection();
__request.Headers.Add("Cache-Control", "no-cache");
使用AspNetCacheProfile属性标记您的服务操作:
[AspNetCacheProfile("GetContent")]  
public ResultABC GetContent(string abc)  
{  
  __request = (HttpWebRequest)WebRequest.Create(abc);
  return __request;  
}

并更新您的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>

选项2是避免从客户端缓存中检索结果的正确方法。 - Darrel Miller

5

我基于上面的解决方案编写了一个基于HttpMessageHandler的程序:

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

使用 new HttpClient(new BypassCacheHttpRequestHandler(), true); 来初始化你的 HttpClient,然后你就可以始终绕过缓存。

1
或者你可以直接设置HttpClient.DefaultRequestHeader。此外,更正确的做法是httpClient.DefaultRequestHeader.CacheControl = new CacheControlHeaderValue() {NoCache=true}; - Darrel Miller

5
这是为了Windows Phone获取新数据而不是缓存数据:

这是为了Windows Phone获得最新的数据而不是缓存数据。

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

另一种选择是设置

Response.Cache.SetCacheability(HttpCacheability.NoCache);

在服务器页面 Page_Load 中,如果您从 aspx 页面获取数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接