This only clears items in the user cache:
这只清除用户缓存中的项目:
public static void ClearCache()
{
foreach (DictionaryEntry entry in HttpRuntime.Cache)
{
HttpRuntime.Cache.Remove(entry.Key.ToString());
}
}
Is there any way to access the kernel cache as well?
有没有办法访问内核缓存?
Clarification: I want to print the keys of all items in the kernel cache, and as a bonus I'd like to be able to clear the kernel cache from a C# method as well.
澄清:我想打印内核缓存中所有项的键,作为奖励,我希望能够从C#方法中清除内核缓存。
2 个解决方案
#1
11
Yep, it's possible to programmatically enumerate and remove items from IIS's kernel cache.
是的,可以通过编程方式枚举和删除IIS内核缓存中的项目。
Caveats:
- non-trivial text parsing requred for enumeration
- lots of ugly P/Invoke required for removal
- Also, you'll need at least Medium Trust (and probably Full Trust) to do the things below.
- Removal won't work in IIS's integrated pipeline mode.
- Enumeration probably won't work on IIS6
需要进行枚举的非平凡文本解析
删除需要很多丑陋的P / Invoke
此外,您至少需要中等信任(可能还有完全信任)才能完成以下任务。
删除在IIS的集成管道模式下不起作用。
枚举可能不适用于IIS6
Enumeration:
The only documented way I know to enumerate the IIS kernel cache is a command-line app available in IIS7 and above (although you might be able to copy the NETSH helper DLL from V7 onto a V6 system-- haven't tried it).
我知道枚举IIS内核缓存的唯一记录方式是IIS7及更高版本中可用的命令行应用程序(尽管您可以将NETSH帮助程序DLL从V7复制到V6系统 - 尚未尝试过)。
netsh http show cachestate
See MSDN Documentation of the show cachestate command for more details. You could turn this into an "API" by executing the process and parsing the text results.
有关更多详细信息,请参阅show cachestate命令的MSDN文档。您可以通过执行该过程并解析文本结果将其转换为“API”。
Big Caveat: I've never seen this command-line app actually return anything on my server, even for apps running in Classic mode. Not sure why-- but the app does work as I can see from other postings online. (e.g. http://chrison.net/ViewingTheKernelCache.aspx)
Big Caveat:我从未见过这个命令行应用实际上在我的服务器上返回任何内容,即使是在经典模式下运行的应用程序。不知道为什么 - 但应用程序确实有效,因为我可以从其他在线帖子中看到。 (例如http://chrison.net/ViewingTheKernelCache.aspx)
If you're horribly allergic to process creation and feeling ambitious, NETSH commands are implemented by DLL's with a documented Win32 interface, so you could write code which pretends it's NETSH.exe and calls into IIS's NETSH helper DLL directly. You can use the documentation on MSDN as a starting point for this approach. Warning: impersonating NETSH is non-trivially hard since the interface is 2-way: NETSH calls into the DLL and the DLL calls back into NETSH. And you'd still have to parse text output since the NETSH interface is text-based, not object-based like PowerShell or WMI. If it were me, I'd just spawn a NETSH process instead. ;-)
如果你对创建过程非常过敏并且有野心勃勃的感觉,那么NETSH命令是由带有文档化的Win32接口的DLL实现的,因此你可以编写假装它的NETSH.exe并直接调用IIS的NETSH帮助DLL的代码。您可以使用MSDN上的文档作为此方法的起点。警告:模拟NETSH是非常困难的,因为接口是双向的:NETSH调用DLL并且DLL调用回NETSH。而且你仍然必须解析文本输出,因为NETSH接口是基于文本的,而不是基于对象的,如PowerShell或WMI。如果是我,我只会产生一个NETSH流程。 ;-)
It's possible that the IIS7 PowerShell snapin may support this functionality in the future (meaning easier programmatic access than the hacks above), but AFAIK only NETSH supports this feature today.
IIS7 PowerShell管理单元可能在将来支持此功能(意味着比上面的hacks更容易编程访问),但AFAIK今天只有NETSH支持此功能。
Invalidation:
I've got good news and bad news for you.
我有好消息和坏消息给你。
The good news: Once you know the URL of the item you want to yank from IIS's kernel cache, there's a Win32 API available to remove it on IIS6 and above. This can be called from C# via P/Invoke (harder) or by putting the call in a managed C++ wrapper DLL. See HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK on MSDN for details.
好消息:一旦你知道要从IIS的内核缓存中提取的项目的URL,就可以在IIS6及更高版本上使用Win32 API将其删除。这可以通过P / Invoke(更难)从C#调用,也可以通过将调用放在托管C ++包装器DLL中调用。有关详细信息,请参阅MSDN上的HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK。
I took a stab at the code required (attached below). Warning: it's ugly and untested-- it doesn't crash my IIS but (see above) I can't figure out how to get cache enumeration working so I can't actually call it with a valid URL to pull from the cache. If you can get enumeration working, then plugging in a valid URL (and hence testing this code) should be easy.
我接受了所需的代码(附在下面)。警告:它很丑陋且未经测试 - 它不会使我的IIS崩溃但是(见上文)我无法弄清楚如何使缓存枚举工作,所以我实际上无法使用有效的URL来调用它来从缓存中提取。如果您可以使枚举工作,那么插入有效的URL(并因此测试此代码)应该很容易。
The bad news:
坏消息:
- as you can guess from the code sample, it won't work on IIS7's integrated pipeline mode, only in Classic mode (or IIS6, of course) where ASP.NET runs as an ISAPI and has access to ISAPI functions
- messing with private fields is a big hack and may break in a new version
- P/Invoke is hard to deal with and requires (I believe) full trust
正如您可以从代码示例中猜到的那样,它不适用于IIS7的集成管道模式,仅适用于经典模式(当然还有IIS6),其中ASP.NET作为ISAPI运行并且可以访问ISAPI函数
搞乱私人领域是一个很大的问题,可能会破坏新版本
P / Invoke很难处理,需要(我相信)完全信任
Here's some code:
这是一些代码:
using System;
using System.Web;
using System.Reflection;
using System.Runtime.InteropServices;
public partial class Test : System.Web.UI.Page
{
/// Return Type: BOOL->int
public delegate int GetServerVariable();
/// Return Type: BOOL->int
public delegate int WriteClient();
/// Return Type: BOOL->int
public delegate int ReadClient();
/// Return Type: BOOL->int
public delegate int ServerSupportFunction();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_GetServerVariable();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_WriteClient();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_ReadClient();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_ServerSupportFunction();
public static readonly int HSE_LOG_BUFFER_LEN = 80;
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct EXTENSION_CONTROL_BLOCK
{
/// DWORD->unsigned int
public uint cbSize;
/// DWORD->unsigned int
public uint dwVersion;
/// DWORD->unsigned int
public uint connID;
/// DWORD->unsigned int
public uint dwHttpStatusCode;
/// CHAR[HSE_LOG_BUFFER_LEN]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 80 /*HSE_LOG_BUFFER_LEN*/)]
public string lpszLogData;
/// LPSTR->CHAR*
public System.IntPtr lpszMethod;
/// LPSTR->CHAR*
public System.IntPtr lpszQueryString;
/// LPSTR->CHAR*
public System.IntPtr lpszPathInfo;
/// LPSTR->CHAR*
public System.IntPtr lpszPathTranslated;
/// DWORD->unsigned int
public uint cbTotalBytes;
/// DWORD->unsigned int
public uint cbAvailable;
/// LPBYTE->BYTE*
public System.IntPtr lpbData;
/// LPSTR->CHAR*
public System.IntPtr lpszContentType;
/// EXTENSION_CONTROL_BLOCK_GetServerVariable
public EXTENSION_CONTROL_BLOCK_GetServerVariable GetServerVariable;
/// EXTENSION_CONTROL_BLOCK_WriteClient
public EXTENSION_CONTROL_BLOCK_WriteClient WriteClient;
/// EXTENSION_CONTROL_BLOCK_ReadClient
public EXTENSION_CONTROL_BLOCK_ReadClient ReadClient;
/// EXTENSION_CONTROL_BLOCK_ServerSupportFunction
// changed to specific signiature for invalidation callback
public ServerSupportFunction_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK ServerSupportFunction;
}
/// Return Type: BOOL->int
///ConnID: DWORD->unsigned int
///dwServerSupportFunction: DWORD->unsigned int
///lpvBuffer: LPVOID->void*
///lpdwSize: LPDWORD->DWORD*
///lpdwDataType: LPDWORD->DWORD*
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public delegate bool ServerSupportFunction_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK(
uint ConnID,
uint dwServerSupportFunction, // must be HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK
out Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK lpvBuffer,
out uint lpdwSize,
out uint lpdwDataType);
public readonly uint HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK = 1040;
// typedef HRESULT (WINAPI * PFN_HSE_CACHE_INVALIDATION_CALLBACK)(WCHAR *pszUrl);
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public delegate bool Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK(
[MarshalAs(UnmanagedType.LPWStr)]string url);
object GetField (Type t, object o, string fieldName)
{
FieldInfo fld = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
return fld == null ? null : fld.GetValue(o);
}
protected void Page_Load(object sender, EventArgs e)
{
// first, get the ECB from the ISAPIWorkerRequest
var ctx = HttpContext.Current;
HttpWorkerRequest wr = (HttpWorkerRequest) GetField(typeof(HttpContext), ctx, "_wr");
IntPtr ecbPtr = IntPtr.Zero;
for (var t = wr.GetType(); t != null && t != typeof(object); t = t.BaseType)
{
object o = GetField(t, wr, "_ecb");
if (o != null)
{
ecbPtr = (IntPtr)o;
break;
}
}
// now call the ECB callback function to remove the item from cache
if (ecbPtr != IntPtr.Zero)
{
EXTENSION_CONTROL_BLOCK ecb = (EXTENSION_CONTROL_BLOCK)Marshal.PtrToStructure(
ecbPtr, typeof(EXTENSION_CONTROL_BLOCK));
uint dummy1, dummy2;
Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK invalidationCallback;
ecb.ServerSupportFunction(ecb.connID,
HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK,
out invalidationCallback,
out dummy1,
out dummy2);
bool success = invalidationCallback("/this/is/a/test");
}
}
}
#2
0
From the discussion link you provided, it appears that the cache method or property exists but is protected or private so you can't access it.
从您提供的讨论链接看来,缓存方法或属性似乎存在但受保护或私有,因此您无法访问它。
Normally, you should stay away from using methods that are not part of the public API, but if you want to access them, use Reflection. With reflection, you can call private methods and get or set private properties and fields.
通常,您应该远离使用不属于公共API的方法,但如果要访问它们,请使用Reflection。通过反射,您可以调用私有方法并获取或设置私有属性和字段。
#1
11
Yep, it's possible to programmatically enumerate and remove items from IIS's kernel cache.
是的,可以通过编程方式枚举和删除IIS内核缓存中的项目。
Caveats:
- non-trivial text parsing requred for enumeration
- lots of ugly P/Invoke required for removal
- Also, you'll need at least Medium Trust (and probably Full Trust) to do the things below.
- Removal won't work in IIS's integrated pipeline mode.
- Enumeration probably won't work on IIS6
需要进行枚举的非平凡文本解析
删除需要很多丑陋的P / Invoke
此外,您至少需要中等信任(可能还有完全信任)才能完成以下任务。
删除在IIS的集成管道模式下不起作用。
枚举可能不适用于IIS6
Enumeration:
The only documented way I know to enumerate the IIS kernel cache is a command-line app available in IIS7 and above (although you might be able to copy the NETSH helper DLL from V7 onto a V6 system-- haven't tried it).
我知道枚举IIS内核缓存的唯一记录方式是IIS7及更高版本中可用的命令行应用程序(尽管您可以将NETSH帮助程序DLL从V7复制到V6系统 - 尚未尝试过)。
netsh http show cachestate
See MSDN Documentation of the show cachestate command for more details. You could turn this into an "API" by executing the process and parsing the text results.
有关更多详细信息,请参阅show cachestate命令的MSDN文档。您可以通过执行该过程并解析文本结果将其转换为“API”。
Big Caveat: I've never seen this command-line app actually return anything on my server, even for apps running in Classic mode. Not sure why-- but the app does work as I can see from other postings online. (e.g. http://chrison.net/ViewingTheKernelCache.aspx)
Big Caveat:我从未见过这个命令行应用实际上在我的服务器上返回任何内容,即使是在经典模式下运行的应用程序。不知道为什么 - 但应用程序确实有效,因为我可以从其他在线帖子中看到。 (例如http://chrison.net/ViewingTheKernelCache.aspx)
If you're horribly allergic to process creation and feeling ambitious, NETSH commands are implemented by DLL's with a documented Win32 interface, so you could write code which pretends it's NETSH.exe and calls into IIS's NETSH helper DLL directly. You can use the documentation on MSDN as a starting point for this approach. Warning: impersonating NETSH is non-trivially hard since the interface is 2-way: NETSH calls into the DLL and the DLL calls back into NETSH. And you'd still have to parse text output since the NETSH interface is text-based, not object-based like PowerShell or WMI. If it were me, I'd just spawn a NETSH process instead. ;-)
如果你对创建过程非常过敏并且有野心勃勃的感觉,那么NETSH命令是由带有文档化的Win32接口的DLL实现的,因此你可以编写假装它的NETSH.exe并直接调用IIS的NETSH帮助DLL的代码。您可以使用MSDN上的文档作为此方法的起点。警告:模拟NETSH是非常困难的,因为接口是双向的:NETSH调用DLL并且DLL调用回NETSH。而且你仍然必须解析文本输出,因为NETSH接口是基于文本的,而不是基于对象的,如PowerShell或WMI。如果是我,我只会产生一个NETSH流程。 ;-)
It's possible that the IIS7 PowerShell snapin may support this functionality in the future (meaning easier programmatic access than the hacks above), but AFAIK only NETSH supports this feature today.
IIS7 PowerShell管理单元可能在将来支持此功能(意味着比上面的hacks更容易编程访问),但AFAIK今天只有NETSH支持此功能。
Invalidation:
I've got good news and bad news for you.
我有好消息和坏消息给你。
The good news: Once you know the URL of the item you want to yank from IIS's kernel cache, there's a Win32 API available to remove it on IIS6 and above. This can be called from C# via P/Invoke (harder) or by putting the call in a managed C++ wrapper DLL. See HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK on MSDN for details.
好消息:一旦你知道要从IIS的内核缓存中提取的项目的URL,就可以在IIS6及更高版本上使用Win32 API将其删除。这可以通过P / Invoke(更难)从C#调用,也可以通过将调用放在托管C ++包装器DLL中调用。有关详细信息,请参阅MSDN上的HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK。
I took a stab at the code required (attached below). Warning: it's ugly and untested-- it doesn't crash my IIS but (see above) I can't figure out how to get cache enumeration working so I can't actually call it with a valid URL to pull from the cache. If you can get enumeration working, then plugging in a valid URL (and hence testing this code) should be easy.
我接受了所需的代码(附在下面)。警告:它很丑陋且未经测试 - 它不会使我的IIS崩溃但是(见上文)我无法弄清楚如何使缓存枚举工作,所以我实际上无法使用有效的URL来调用它来从缓存中提取。如果您可以使枚举工作,那么插入有效的URL(并因此测试此代码)应该很容易。
The bad news:
坏消息:
- as you can guess from the code sample, it won't work on IIS7's integrated pipeline mode, only in Classic mode (or IIS6, of course) where ASP.NET runs as an ISAPI and has access to ISAPI functions
- messing with private fields is a big hack and may break in a new version
- P/Invoke is hard to deal with and requires (I believe) full trust
正如您可以从代码示例中猜到的那样,它不适用于IIS7的集成管道模式,仅适用于经典模式(当然还有IIS6),其中ASP.NET作为ISAPI运行并且可以访问ISAPI函数
搞乱私人领域是一个很大的问题,可能会破坏新版本
P / Invoke很难处理,需要(我相信)完全信任
Here's some code:
这是一些代码:
using System;
using System.Web;
using System.Reflection;
using System.Runtime.InteropServices;
public partial class Test : System.Web.UI.Page
{
/// Return Type: BOOL->int
public delegate int GetServerVariable();
/// Return Type: BOOL->int
public delegate int WriteClient();
/// Return Type: BOOL->int
public delegate int ReadClient();
/// Return Type: BOOL->int
public delegate int ServerSupportFunction();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_GetServerVariable();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_WriteClient();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_ReadClient();
/// Return Type: BOOL->int
public delegate int EXTENSION_CONTROL_BLOCK_ServerSupportFunction();
public static readonly int HSE_LOG_BUFFER_LEN = 80;
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct EXTENSION_CONTROL_BLOCK
{
/// DWORD->unsigned int
public uint cbSize;
/// DWORD->unsigned int
public uint dwVersion;
/// DWORD->unsigned int
public uint connID;
/// DWORD->unsigned int
public uint dwHttpStatusCode;
/// CHAR[HSE_LOG_BUFFER_LEN]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 80 /*HSE_LOG_BUFFER_LEN*/)]
public string lpszLogData;
/// LPSTR->CHAR*
public System.IntPtr lpszMethod;
/// LPSTR->CHAR*
public System.IntPtr lpszQueryString;
/// LPSTR->CHAR*
public System.IntPtr lpszPathInfo;
/// LPSTR->CHAR*
public System.IntPtr lpszPathTranslated;
/// DWORD->unsigned int
public uint cbTotalBytes;
/// DWORD->unsigned int
public uint cbAvailable;
/// LPBYTE->BYTE*
public System.IntPtr lpbData;
/// LPSTR->CHAR*
public System.IntPtr lpszContentType;
/// EXTENSION_CONTROL_BLOCK_GetServerVariable
public EXTENSION_CONTROL_BLOCK_GetServerVariable GetServerVariable;
/// EXTENSION_CONTROL_BLOCK_WriteClient
public EXTENSION_CONTROL_BLOCK_WriteClient WriteClient;
/// EXTENSION_CONTROL_BLOCK_ReadClient
public EXTENSION_CONTROL_BLOCK_ReadClient ReadClient;
/// EXTENSION_CONTROL_BLOCK_ServerSupportFunction
// changed to specific signiature for invalidation callback
public ServerSupportFunction_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK ServerSupportFunction;
}
/// Return Type: BOOL->int
///ConnID: DWORD->unsigned int
///dwServerSupportFunction: DWORD->unsigned int
///lpvBuffer: LPVOID->void*
///lpdwSize: LPDWORD->DWORD*
///lpdwDataType: LPDWORD->DWORD*
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public delegate bool ServerSupportFunction_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK(
uint ConnID,
uint dwServerSupportFunction, // must be HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK
out Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK lpvBuffer,
out uint lpdwSize,
out uint lpdwDataType);
public readonly uint HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK = 1040;
// typedef HRESULT (WINAPI * PFN_HSE_CACHE_INVALIDATION_CALLBACK)(WCHAR *pszUrl);
[return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
public delegate bool Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK(
[MarshalAs(UnmanagedType.LPWStr)]string url);
object GetField (Type t, object o, string fieldName)
{
FieldInfo fld = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
return fld == null ? null : fld.GetValue(o);
}
protected void Page_Load(object sender, EventArgs e)
{
// first, get the ECB from the ISAPIWorkerRequest
var ctx = HttpContext.Current;
HttpWorkerRequest wr = (HttpWorkerRequest) GetField(typeof(HttpContext), ctx, "_wr");
IntPtr ecbPtr = IntPtr.Zero;
for (var t = wr.GetType(); t != null && t != typeof(object); t = t.BaseType)
{
object o = GetField(t, wr, "_ecb");
if (o != null)
{
ecbPtr = (IntPtr)o;
break;
}
}
// now call the ECB callback function to remove the item from cache
if (ecbPtr != IntPtr.Zero)
{
EXTENSION_CONTROL_BLOCK ecb = (EXTENSION_CONTROL_BLOCK)Marshal.PtrToStructure(
ecbPtr, typeof(EXTENSION_CONTROL_BLOCK));
uint dummy1, dummy2;
Callback_HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK invalidationCallback;
ecb.ServerSupportFunction(ecb.connID,
HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK,
out invalidationCallback,
out dummy1,
out dummy2);
bool success = invalidationCallback("/this/is/a/test");
}
}
}
#2
0
From the discussion link you provided, it appears that the cache method or property exists but is protected or private so you can't access it.
从您提供的讨论链接看来,缓存方法或属性似乎存在但受保护或私有,因此您无法访问它。
Normally, you should stay away from using methods that are not part of the public API, but if you want to access them, use Reflection. With reflection, you can call private methods and get or set private properties and fields.
通常,您应该远离使用不属于公共API的方法,但如果要访问它们,请使用Reflection。通过反射,您可以调用私有方法并获取或设置私有属性和字段。