C# Net中的缓存和WebBrowser控件
我正在使用.Net中的WebBrowser控件执行一些第三方联盟营销转换 我在数据库中有一个队列表,其中包含所有要执行的脚本/图像。我在带有WebBrowser控件的WinForms应用程序中循环浏览所有这些内容。在执行脚本/映像后,我将处理WebBrowser控件,将其设置为null,并使用新的WebBrowser控件实例更新它 考虑以下URL: RenderScript.aspx显示URL为的图像,例如: 我使用Fiddler查看所有请求和响应,当同一URL执行两次时,它使用某种缓存。该缓存存在于WebBrowser控件本身之下 此缓存意味着不调用img.ashx 我尝试使用Internet Explorer请求URL:并点击F5。然后它被完美地要求 但是,如果我点击地址栏并点击回车键再次导航到同一个URL,它将不会被请求。当我使用Firefox时,无论我使用F5还是从地址栏导航,它都会每次请求页面和图像 我发现一些Win32 API调用()能够清除缓存。它在我本地的机器上工作。然后,该应用程序被部署到运行Windows server 2003标准x64的服务器上(我自己的机器是Vista x86) 现在清除缓存的API调用不起作用C# Net中的缓存和WebBrowser控件,c#,winforms,webbrowser-control,C#,Winforms,Webbrowser Control,我正在使用.Net中的WebBrowser控件执行一些第三方联盟营销转换 我在数据库中有一个队列表,其中包含所有要执行的脚本/图像。我在带有WebBrowser控件的WinForms应用程序中循环浏览所有这些内容。在执行脚本/映像后,我将处理WebBrowser控件,将其设置为null,并使用新的WebBrowser控件实例更新它 考虑以下URL: RenderScript.aspx显示URL为的图像,例如: 我使用Fiddler查看所有请求和响应,当同一URL执行两次时,它使用某种缓存。该缓存
你知道为什么API调用在Windows Server上不起作用,但在Vista上起作用吗?两台运行IE8的机器。Fiddler使用与KB文章中基本相同的代码来清除WinINET缓存,我每天都在Win2k3上使用它 正确的修复方法不是擦除用户的整个缓存,而是将正确的HTTP响应头设置为禁止缓存。您可以在此处了解有关WinINET缓存的更多信息:
(或者,您可以简单地添加一个随机查询字符串参数;这样,每次控件遇到资源请求时,URL都会不同,因此缓存会自动绕过。)这应该可以做到:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
试试这个
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
private const int INTERNET_OPTION_END_BROWSER_SESSION = 42;
private void clearCache()
{
try
{
Utilities.Web.WebBrowserHelper.WebBrowserHelper.ClearCache();
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_END_BROWSER_SESSION, IntPtr.Zero, 0);
}
catch (Exception exception)
{
//throw;
}
}
不久前我也有同样的问题。Microsoft有一个页面对此非常有帮助:
我用微软的示例创建了一个类,但是我还必须添加几个if语句,以便在没有更多项时停止处理;已经有一段时间了,但我很确定它会抛出一个错误(请参见下面代码中的error\u NO\u MORE\u ITEMS
)
我希望它有帮助
using System;
using System.Runtime.InteropServices;
// copied from: http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q326/2/01.asp&NoWebContent=1
namespace PowerCode
{
public class IECache
{
// For PInvoke: Contains information about an entry in the Internet cache
[StructLayout(LayoutKind.Explicit, Size = 80)]
public struct INTERNET_CACHE_ENTRY_INFOA
{
[FieldOffset(0)]
public uint dwStructSize;
[FieldOffset(4)]
public IntPtr lpszSourceUrlName;
[FieldOffset(8)]
public IntPtr lpszLocalFileName;
[FieldOffset(12)]
public uint CacheEntryType;
[FieldOffset(16)]
public uint dwUseCount;
[FieldOffset(20)]
public uint dwHitRate;
[FieldOffset(24)]
public uint dwSizeLow;
[FieldOffset(28)]
public uint dwSizeHigh;
[FieldOffset(32)]
public FILETIME LastModifiedTime;
[FieldOffset(40)]
public FILETIME ExpireTime;
[FieldOffset(48)]
public FILETIME LastAccessTime;
[FieldOffset(56)]
public FILETIME LastSyncTime;
[FieldOffset(64)]
public IntPtr lpHeaderInfo;
[FieldOffset(68)]
public uint dwHeaderInfoSize;
[FieldOffset(72)]
public IntPtr lpszFileExtension;
[FieldOffset(76)]
public uint dwReserved;
[FieldOffset(76)]
public uint dwExemptDelta;
}
// For PInvoke: Initiates the enumeration of the cache groups in the Internet cache
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindFirstUrlCacheGroup", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr FindFirstUrlCacheGroup( int dwFlags, int dwFilter, IntPtr lpSearchCondition, int dwSearchCondition, ref long lpGroupId, IntPtr lpReserved );
// For PInvoke: Retrieves the next cache group in a cache group enumeration
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindNextUrlCacheGroup", CallingConvention = CallingConvention.StdCall)]
public static extern bool FindNextUrlCacheGroup( IntPtr hFind, ref long lpGroupId, IntPtr lpReserved );
// For PInvoke: Releases the specified GROUPID and any associated state in the cache index file
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "DeleteUrlCacheGroup", CallingConvention = CallingConvention.StdCall)]
public static extern bool DeleteUrlCacheGroup( long GroupId, int dwFlags, IntPtr lpReserved );
// For PInvoke: Begins the enumeration of the Internet cache
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindFirstUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr FindFirstUrlCacheEntry( [MarshalAs(UnmanagedType.LPTStr)] string lpszUrlSearchPattern, IntPtr lpFirstCacheEntryInfo, ref int lpdwFirstCacheEntryInfoBufferSize );
// For PInvoke: Retrieves the next entry in the Internet cache
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "FindNextUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)]
public static extern bool FindNextUrlCacheEntry( IntPtr hFind, IntPtr lpNextCacheEntryInfo, ref int lpdwNextCacheEntryInfoBufferSize );
// For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists
[DllImport(@"wininet", SetLastError = true, CharSet = CharSet.Auto, EntryPoint = "DeleteUrlCacheEntryA", CallingConvention = CallingConvention.StdCall)]
public static extern bool DeleteUrlCacheEntry( IntPtr lpszUrlName );
public static void ClearCache()
{
// Indicates that all of the cache groups in the user's system should be enumerated
const int CACHEGROUP_SEARCH_ALL = 0x0;
// Indicates that all the cache entries that are associated with the cache group
// should be deleted, unless the entry belongs to another cache group.
const int CACHEGROUP_FLAG_FLUSHURL_ONDELETE = 0x2;
// File not found.
const int ERROR_FILE_NOT_FOUND = 0x2;
// No more items have been found.
const int ERROR_NO_MORE_ITEMS = 259;
// Pointer to a GROUPID variable
long groupId = 0;
// Local variables
int cacheEntryInfoBufferSizeInitial = 0;
int cacheEntryInfoBufferSize = 0;
IntPtr cacheEntryInfoBuffer = IntPtr.Zero;
INTERNET_CACHE_ENTRY_INFOA internetCacheEntry;
IntPtr enumHandle = IntPtr.Zero;
bool returnValue = false;
// Delete the groups first.
// Groups may not always exist on the system.
// For more information, visit the following Microsoft Web site:
// http://msdn.microsoft.com/library/?url=/workshop/networking/wininet/overview/cache.asp
// By default, a URL does not belong to any group. Therefore, that cache may become
// empty even when the CacheGroup APIs are not used because the existing URL does not belong to any group.
enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero);
// If there are no items in the Cache, you are finished.
if (enumHandle != IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) {
return;
}
// Loop through Cache Group, and then delete entries.
while (true) {
if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()) {
break;
}
// Delete a particular Cache Group.
returnValue = DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero);
if (!returnValue && ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()) {
returnValue = FindNextUrlCacheGroup(enumHandle, ref groupId, IntPtr.Zero);
}
if (!returnValue && (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error())) {
break;
}
}
// Start to delete URLs that do not belong to any group.
enumHandle = FindFirstUrlCacheEntry(null, IntPtr.Zero, ref cacheEntryInfoBufferSizeInitial);
if (enumHandle != IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) {
return;
}
cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial;
cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize);
enumHandle = FindFirstUrlCacheEntry(null, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
while (true) {
internetCacheEntry = (INTERNET_CACHE_ENTRY_INFOA)Marshal.PtrToStructure(cacheEntryInfoBuffer, typeof(INTERNET_CACHE_ENTRY_INFOA));
if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) {
break;
}
cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize;
returnValue = DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName);
if (!returnValue) {
returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
}
if (!returnValue && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error()) {
break;
}
if (!returnValue && cacheEntryInfoBufferSizeInitial > cacheEntryInfoBufferSize) {
cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial;
cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, (IntPtr)cacheEntryInfoBufferSize);
returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
}
}
Marshal.FreeHGlobal(cacheEntryInfoBuffer);
}
}
}
要在代码中使用它,只需调用:
IECache.ClearCache()
调用navigate方法之前。everyone链接到的kb文章中有许多错误(所选答案的源代码来自于此),我已经浪费了约2天的时间试图让它在所有必要的设置下工作。它是在互联网上复制粘贴的,并且有许多基于操作系统和IE版本的bug报告 Fiddler最初由Microsoft员工编写,由FiddlerCore.dll提供支持。Fiddler的Telerik(目前的所有者/维护者/销售者)仍然免费更新、维护和赠送FiddlerCore。如果不想添加对FiddlerCore的引用,可以反汇编dll,它显示了调用所有这些可怕的WinINet函数的正确方法,但我认为在这里发布它会对Telerik/plagarism造成伤害 目前,Fiddlercore托管在这里:源代码 似乎有马车 在此处检查MSDN文档和VB版本: 我这样修改了代码,现在因为它对我有效(问题是在执行FindNextUrlCacheGroup和FindNextUrlCacheEntry时):
消极的它与缓存头无关。它们已正确设置以避免缓存。正如我指出的,其他浏览器没有缓存,随机参数也不起作用。因为ScriptRender页面加载的第三方HTML完全不受我的控制。因此,我只能将参数添加到RenderScript页面。图像标签(有时是IFrame,有时是javascript)是用静态URL加载的。对不起,你搞错了。如果设置了适当的响应头,WinINET/IE/WebOCs将不会重用缓存的响应。ASHX发送的确切标题是什么?您能给我发送一个网络捕获(www.fiddlercap.com)吗?使用IIS 7.5传送pdf文件,没有缓存控制,WinINET设置为Automtical肯定不会在pdf文件更新时重新请求该文件,并且至少从IE 8开始就被破坏了。@NetMage--您很困惑。如果不存在禁止响应的缓存控制头,则标准指定可以缓存和重用响应。其中是
Utilities.Web.WebBrowserHelper.WebBrowserHelper.ClearCache()代码>定义?它造成了死锁,我认为应该改变!在“if(!returnValue&&ERROR\u FILE\u NOT\u FOUND==Marshal.GetLastWin32Error())”行将returnValue转换为returnValue。
using System;
using System.Runtime.InteropServices;
namespace Q326201CS
{
// Class for deleting the cache.
public class DeleteIECache
{
// For PInvoke: Contains information about an entry in the Internet cache
[StructLayout(LayoutKind.Explicit, Size=80)]
public struct INTERNET_CACHE_ENTRY_INFOA
{
[FieldOffset(0)] public uint dwStructSize;
[FieldOffset(4)] public IntPtr lpszSourceUrlName;
[FieldOffset(8)] public IntPtr lpszLocalFileName;
[FieldOffset(12)] public uint CacheEntryType;
[FieldOffset(16)] public uint dwUseCount;
[FieldOffset(20)] public uint dwHitRate;
[FieldOffset(24)] public uint dwSizeLow;
[FieldOffset(28)] public uint dwSizeHigh;
[FieldOffset(32)] public FILETIME LastModifiedTime;
[FieldOffset(40)] public FILETIME ExpireTime;
[FieldOffset(48)] public FILETIME LastAccessTime;
[FieldOffset(56)] public FILETIME LastSyncTime;
[FieldOffset(64)] public IntPtr lpHeaderInfo;
[FieldOffset(68)] public uint dwHeaderInfoSize;
[FieldOffset(72)] public IntPtr lpszFileExtension;
[FieldOffset(76)] public uint dwReserved;
[FieldOffset(76)] public uint dwExemptDelta;
}
// For PInvoke: Initiates the enumeration of the cache groups in the Internet cache
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="FindFirstUrlCacheGroup",
CallingConvention=CallingConvention.StdCall)]
public static extern IntPtr FindFirstUrlCacheGroup(
int dwFlags,
int dwFilter,
IntPtr lpSearchCondition,
int dwSearchCondition,
ref long lpGroupId,
IntPtr lpReserved);
// For PInvoke: Retrieves the next cache group in a cache group enumeration
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="FindNextUrlCacheGroup",
CallingConvention=CallingConvention.StdCall)]
public static extern bool FindNextUrlCacheGroup(
IntPtr hFind,
ref long lpGroupId,
IntPtr lpReserved);
// For PInvoke: Releases the specified GROUPID and any associated state in the cache index file
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="DeleteUrlCacheGroup",
CallingConvention=CallingConvention.StdCall)]
public static extern bool DeleteUrlCacheGroup(
long GroupId,
int dwFlags,
IntPtr lpReserved);
// For PInvoke: Begins the enumeration of the Internet cache
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="FindFirstUrlCacheEntryA",
CallingConvention=CallingConvention.StdCall)]
public static extern IntPtr FindFirstUrlCacheEntry(
[MarshalAs(UnmanagedType.LPTStr)] string lpszUrlSearchPattern,
IntPtr lpFirstCacheEntryInfo,
ref int lpdwFirstCacheEntryInfoBufferSize);
// For PInvoke: Retrieves the next entry in the Internet cache
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="FindNextUrlCacheEntryA",
CallingConvention=CallingConvention.StdCall)]
public static extern bool FindNextUrlCacheEntry(
IntPtr hFind,
IntPtr lpNextCacheEntryInfo,
ref int lpdwNextCacheEntryInfoBufferSize);
// For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists
[DllImport(@"wininet",
SetLastError=true,
CharSet=CharSet.Auto,
EntryPoint="DeleteUrlCacheEntryA",
CallingConvention=CallingConvention.StdCall)]
public static extern bool DeleteUrlCacheEntry(
IntPtr lpszUrlName);
public static void doDelete()
{
// Indicates that all of the cache groups in the user's system should be enumerated
const int CACHEGROUP_SEARCH_ALL = 0x0;
// Indicates that all the cache entries that are associated with the cache group
// should be deleted, unless the entry belongs to another cache group.
const int CACHEGROUP_FLAG_FLUSHURL_ONDELETE = 0x2;
// File not found.
const int ERROR_FILE_NOT_FOUND = 0x2;
// No more items have been found.
const int ERROR_NO_MORE_ITEMS = 259;
// Pointer to a GROUPID variable
long groupId = 0;
// Local variables
int cacheEntryInfoBufferSizeInitial = 0;
int cacheEntryInfoBufferSize = 0;
IntPtr cacheEntryInfoBuffer = IntPtr.Zero;
INTERNET_CACHE_ENTRY_INFOA internetCacheEntry;
IntPtr enumHandle = IntPtr.Zero;
bool returnValue = false;
// Delete the groups first.
// Groups may not always exist on the system.
// For more information, visit the following Microsoft Web site:
// http://msdn.microsoft.com/library/?url=/workshop/networking/wininet/overview/cache.asp
// By default, a URL does not belong to any group. Therefore, that cache may become
// empty even when the CacheGroup APIs are not used because the existing URL does not belong to any group.
enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero);
// If there are no items in the Cache, you are finished.
if (enumHandle != IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error())
return;
// Loop through Cache Group, and then delete entries.
while(true)
{
if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error())
{
break;
}
// Delete a particular Cache Group.
returnValue = DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero);
//if (returnValue || (!returnValue && ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()))
//{
returnValue = FindNextUrlCacheGroup(enumHandle, ref groupId, IntPtr.Zero);
//}
if (!returnValue && (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error() || ERROR_FILE_NOT_FOUND == Marshal.GetLastWin32Error()))
break;
}
// Start to delete URLs that do not belong to any group.
enumHandle = FindFirstUrlCacheEntry(null, IntPtr.Zero, ref cacheEntryInfoBufferSizeInitial);
if (enumHandle == IntPtr.Zero && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error())
return;
cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial;
cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize);
enumHandle = FindFirstUrlCacheEntry(null, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
while(true)
{
internetCacheEntry = (INTERNET_CACHE_ENTRY_INFOA)Marshal.PtrToStructure(cacheEntryInfoBuffer, typeof(INTERNET_CACHE_ENTRY_INFOA));
if (ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error())
{
break;
}
cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize;
returnValue = DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName);
//if (!returnValue)
//{
returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
//}
if (!returnValue && ERROR_NO_MORE_ITEMS == Marshal.GetLastWin32Error())
{
break;
}
if (!returnValue && cacheEntryInfoBufferSizeInitial > cacheEntryInfoBufferSize)
{
cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial;
cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, (IntPtr) cacheEntryInfoBufferSize);
returnValue = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial);
}
}
Marshal.FreeHGlobal(cacheEntryInfoBuffer);
}
}
}