Cuestión de caché de control WebBrowser

Estoy usando el control WebBrowser dentro de un formulario de Windows para mostrar un PDF.

Sin embargo, siempre que se regenera el PDF, el control WebBrowser solo muestra su versión local en caché y no la versión actualizada del servidor.

Estoy usando el método Refresh () que se muestra a continuación para intentar forzar el control para volver a cargar el PDF, pero no funciona:

_webBrowser.Navigate(pdfUrl); _webBrowser.Refresh(WebBrowserRefreshOption.Completely) 

¿Tengo que hacer algo más para forzar la actualización para volver a cargar el PDF desde el servidor?

Sheng Jiang es correcto: se necesita la memoria caché de IE clara mediante progtwigción. Aquí hay un código de muestra que muestra cómo hacer esto en c #: http://www.gutgames.com/post/Clearing-the-Cache-of-a-WebBrowser-Control.aspx

Copia en caso de que la página se desconecte:

 /** * Modified from code originally found here: http://support.microsoft.com/kb/326201 **/ #region Usings using System; using System.Runtime.InteropServices; #endregion namespace Utilities.Web.WebBrowserHelper { ///  /// Class for clearing the cache ///  public static class WebBrowserHelper { #region Definitions/DLL Imports ///  /// 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 System.Runtime.InteropServices.ComTypes.FILETIME LastModifiedTime; [FieldOffset(40)] public System.Runtime.InteropServices.ComTypes.FILETIME ExpireTime; [FieldOffset(48)] public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; [FieldOffset(56)] public System.Runtime.InteropServices.ComTypes.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); #endregion #region Public Static Functions ///  /// Clears the cache of the web browser ///  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); } #endregion } } 

Se basa en gran medida en el artículo de Microsoft KB aquí: http://support.microsoft.com/kb/326201

Y para evitar la pregunta, sí, esto es un gran dolor en el cuello y no, no hay otra forma de evitarlo. ¡Buena suerte!

Además de Serj Sagan, aquí está el código con el manejo de errores extraño simplificado, el bucle infinito eliminado y 32/64 bits capaz.

 /** * Modified from code originally found here: http://support.microsoft.com/kb/326201 **/ public class WebBrowserHelper { #region Definitions/DLL Imports ///  /// For PInvoke: Contains information about an entry in the Internet cache ///  [StructLayout(LayoutKind.Explicit)] public struct ExemptDeltaOrReserverd { [FieldOffset(0)] public UInt32 dwReserved; [FieldOffset(0)] public UInt32 dwExemptDelta; } [StructLayout(LayoutKind.Sequential)] public struct INTERNET_CACHE_ENTRY_INFOA { public UInt32 dwStructSize; public IntPtr lpszSourceUrlName; public IntPtr lpszLocalFileName; public UInt32 CacheEntryType; public UInt32 dwUseCount; public UInt32 dwHitRate; public UInt32 dwSizeLow; public UInt32 dwSizeHigh; public FILETIME LastModifiedTime; public FILETIME ExpireTime; public FILETIME LastAccessTime; public FILETIME LastSyncTime; public IntPtr lpHeaderInfo; public UInt32 dwHeaderInfoSize; public IntPtr lpszFileExtension; public ExemptDeltaOrReserverd dwExemptDeltaOrReserved; } // 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); #endregion ///  /// Clears the cache of the web browser ///  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; const int ERROR_INSUFFICIENT_BUFFER = 0x7A; // 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. long groupId = 0; IntPtr enumHandle = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, ref groupId, IntPtr.Zero); if (enumHandle != IntPtr.Zero) { bool more; do { // Delete a particular Cache Group. DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero); more = FindNextUrlCacheGroup(enumHandle, ref groupId, IntPtr.Zero); } while (more); } // Start to delete URLs that do not belong to any group. int cacheEntryInfoBufferSizeInitial = 0; FindFirstUrlCacheEntry(null, IntPtr.Zero, ref cacheEntryInfoBufferSizeInitial); // should always fail because buffer is too small if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { int cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; IntPtr cacheEntryInfoBuffer = Marshal.AllocHGlobal(cacheEntryInfoBufferSize); enumHandle = FindFirstUrlCacheEntry(null, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); if (enumHandle != IntPtr.Zero) { bool more; do { INTERNET_CACHE_ENTRY_INFOA internetCacheEntry = (INTERNET_CACHE_ENTRY_INFOA)Marshal.PtrToStructure(cacheEntryInfoBuffer, typeof(INTERNET_CACHE_ENTRY_INFOA)); cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize; DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName); more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); if (!more && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial; cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, (IntPtr)cacheEntryInfoBufferSize); more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, ref cacheEntryInfoBufferSizeInitial); } } while (more); } Marshal.FreeHGlobal(cacheEntryInfoBuffer); } } } 

Esta es una extensión de la respuesta de Chris Clark … este código es demasiado importante, creo que el desbordamiento de stack es un lugar más seguro para guardarlo, y además me deshice de los números de línea para usted. Aquí hay un enlace al artículo original de nuevo: http://www.gutgames.com/post/Clearing-the-Cache-of-a-WebBrowser-Control.aspx

Y el código:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace Utilities.Web.WebBrowserHelper { /** * Modified from code originally found here: http://support.microsoft.com/kb/326201 **/ public class WebBrowserHelper { #region Definitions/DLL Imports ///  /// 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 System.Runtime.InteropServices.ComTypes.FILETIME LastModifiedTime; [FieldOffset(40)] public System.Runtime.InteropServices.ComTypes.FILETIME ExpireTime; [FieldOffset(48)] public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; [FieldOffset(56)] public System.Runtime.InteropServices.ComTypes.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); #endregion #region Public Static Functions ///  /// Clears the cache of the web browser ///  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); } #endregion } } 

Dado que WebBrowser (en realidad el motor Trident de IE) usa WinInet para redes, puede usar las API de administración de caché de WinInet para eliminar los archivos en caché antes de navegar.

Agregar a la url una identificación aleatoria para que la url sea única cada vez

Encontramos que borrar el caché por completo lleva demasiado tiempo. Una alternativa que parece funcionar bien (y resuelve el problema en la pregunta original de Actualizar no funciona) es mover la llamada a Actualizar después de que el documento haya terminado de cargarse.

 webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(OnWebBrowserDocumentCompleted); // ... private void OnWebBrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (cacheIsStale) { webBrowser.Refresh(WebBrowserRefreshOption.Completely); } } 

Cómo determinar el valor de cacheIsStale dependerá de su aplicación.

Para evitar el almacenamiento en caché de CSS, puede utilizar un truco astuto al incluir el archivo css:

   

Descarga una nueva copia del css porque el? Date_stuff cambia cada vez.

¿Está incrustado el PDF con una etiqueta de objeto o algo así? Si es así, pedirle al objeto del navegador que se actualice no tendrá ningún efecto; debe hacer un script del visor de PDF para realizar la actualización (por ejemplo, obtener un documento del visor de PDF por ID desde el control del navegador web), ya que eso es lo que lo descargó .

Vescan Petru está en el camino correcto, creo. Borrar las cachés del navegador IE es bastante pesado y no es fácil de usar. Adaptar el código de MS sugerido vinculado por Chris Clark para borrar el archivo específico de la caché parece un poco de código interesante para trabajar, pero la respuesta más simple sería tomar un nuevo nombre de archivo temporal y luego hacer una copia del archivo PDF de destino con ese nombre Luego muestre el archivo temporal, eliminándolo al salir.

Esa es mi solución de trabajo implementada cuando encuentro el mismo problema.

Para aquellos de nosotros que todavía necesitamos escribir VB.NET, porté el código publicado por Serj Sagan y Oliver Bock arriba a VB y descubrí que funciona bien.

Gracias a Dios, este hilo existe, realmente estaba sudando este tema durante mucho tiempo.

  ' ' Modified from code originally found here: http://support.microsoft.com/kb/326201 ' Public Class WebBrowserHelper 

Región “Definiciones / Importaciones DLL”

  '''  ''' For PInvoke: Contains information about an entry In the Internet cache '''   Public Structure ExemptDeltaOrReserverd  Public dwReserved As UInt32  Public dwExemptDelta As UInt32 End Structure  Public Structure INTERNET_CACHE_ENTRY_INFOA Public dwStructSize As UInt32 Public lpszSourceUrlName As IntPtr Public lpszLocalFileName As IntPtr Public CacheEntryType As UInt32 Public dwUseCount As UInt32 Public dwHitRate As UInt32 Public dwSizeLow As UInt32 Public dwSizeHigh As UInt32 Public LastModifiedTime As FILETIME Public ExpireTime As FILETIME Public LastAccessTime As FILETIME Public LastSyncTime As FILETIME Public lpHeaderInfo As IntPtr Public dwHeaderInfoSize As UInt32 Public lpszFileExtension As IntPtr Public dwExemptDeltaOrReserved As ExemptDeltaOrReserverd End Structure ' For PInvoke: Initiates the enumeration Of the cache groups In the Internet cache  Public Shared Function FindFirstUrlCacheGroup(dwFlags As Integer, dwFilter As Integer, lpSearchCondition As IntPtr, dwSearchCondition As Integer, ByRef lpGroupId As Long, lpReserved As IntPtr) As IntPtr End Function ' For PInvoke: Retrieves the Next cache group In a cache group enumeration  Public Shared Function FindNextUrlCacheGroup(hFind As IntPtr, ByRef lpGroupId As Long, lpReserved As IntPtr) As Boolean End Function ' For PInvoke: Releases the specified GROUPID And any associated state In the cache index file  Public Shared Function DeleteUrlCacheGroup(GroupId As Long, dwFlags As Integer, lpReserved As IntPtr) As Boolean End Function ' For PInvoke: Begins the enumeration Of the Internet cache  Public Shared Function FindFirstUrlCacheEntry( lpszUrlSearchPattern As String, lpFirstCacheEntryInfo As IntPtr, ByRef lpdwFirstCacheEntryInfoBufferSize As Integer) As IntPtr End Function ' For PInvoke: Retrieves the Next entry In the Internet cache  Public Shared Function FindNextUrlCacheEntry(hFind As IntPtr, lpNextCacheEntryInfo As IntPtr, ByRef lpdwNextCacheEntryInfoBufferSize As Integer) As Boolean End Function ' For PInvoke: Removes the file that Is associated With the source name from the cache, If the file exists  Public Shared Function DeleteUrlCacheEntry(lpszUrlName As IntPtr) As Boolean End Function 

Región final

  '''  ''' Clears the cache of the web browser '''  Public Shared Sub ClearCache() ' Indicates that all of the cache groups in the user's system should be enumerated Const CACHEGROUP_SEARCH_ALL As Integer = &H0 ' 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 CACHEGROUP_FLAG_FLUSHURL_ONDELETE As Integer = &H2 Const ERROR_INSUFFICIENT_BUFFER As Integer = &H7A ' 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. Dim groupId As Long = 0 Dim enumHandle As IntPtr = FindFirstUrlCacheGroup(0, CACHEGROUP_SEARCH_ALL, IntPtr.Zero, 0, groupId, IntPtr.Zero) If (enumHandle <> IntPtr.Zero) Then Dim more As Boolean Do ' Delete a particular Cache Group. DeleteUrlCacheGroup(groupId, CACHEGROUP_FLAG_FLUSHURL_ONDELETE, IntPtr.Zero) more = FindNextUrlCacheGroup(enumHandle, groupId, IntPtr.Zero) Loop While (more) End If ' Start to delete URLs that do Not belong to any group. Dim cacheEntryInfoBufferSizeInitial As Integer = 0 FindFirstUrlCacheEntry(Nothing, IntPtr.Zero, cacheEntryInfoBufferSizeInitial) ' should always fail because buffer Is too small If Marshal.GetLastWin32Error() = ERROR_INSUFFICIENT_BUFFER Then Dim cacheEntryInfoBufferSize As Integer = cacheEntryInfoBufferSizeInitial Dim cacheEntryInfoBuffer As IntPtr = Marshal.AllocHGlobal(cacheEntryInfoBufferSize) enumHandle = FindFirstUrlCacheEntry(Nothing, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) If (enumHandle <> IntPtr.Zero) Then Dim more As Boolean Do Dim internetCacheEntry As INTERNET_CACHE_ENTRY_INFOA = CType(Marshal.PtrToStructure(cacheEntryInfoBuffer, GetType(INTERNET_CACHE_ENTRY_INFOA)), INTERNET_CACHE_ENTRY_INFOA) cacheEntryInfoBufferSizeInitial = cacheEntryInfoBufferSize DeleteUrlCacheEntry(internetCacheEntry.lpszSourceUrlName) more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) If Not more AndAlso Marshal.GetLastWin32Error() = ERROR_INSUFFICIENT_BUFFER Then cacheEntryInfoBufferSize = cacheEntryInfoBufferSizeInitial cacheEntryInfoBuffer = Marshal.ReAllocHGlobal(cacheEntryInfoBuffer, CType(cacheEntryInfoBufferSize, IntPtr)) more = FindNextUrlCacheEntry(enumHandle, cacheEntryInfoBuffer, cacheEntryInfoBufferSizeInitial) End If Loop While (more) End If Marshal.FreeHGlobal(cacheEntryInfoBuffer) End If End Sub End Class