asp.net - 有什么方法可以从 ASP.NET 访问 IIS 内核缓存?

标签 asp.net iis-7 caching iis-6

这只会清除用户缓存中的项目:

    public static void ClearCache()
    {
        foreach (DictionaryEntry entry in HttpRuntime.Cache)
        {
            HttpRuntime.Cache.Remove(entry.Key.ToString());
        }
    }

有没有办法访问内核缓存?

澄清:我想打印内核缓存中所有项目的键,作为奖励,我还希望能够从 C# 方法中清除内核缓存。

最佳答案

是的,可以以编程方式从 IIS 的内核缓存中枚举和删除项目。

注意事项:

  • 枚举需要非平凡的文本解析
  • 删除需要大量丑陋的 P/Invoke
  • 此外,您至少需要中等信任(可能还有完全信任)才能执行以下操作。
  • 删除在 IIS 的集成管道模式下不起作用。
  • 枚举可能不适用于 IIS6

  • 枚举:

    我知道枚举 IIS 内核缓存的唯一记录方法是 IIS7 及更高版本中可用的命令行应用程序(尽管您可能能够将 NETSH 帮助程序 DLL 从 V7 复制到 V6 系统——还没有尝试过)。
    netsh http show cachestate
    

    MSDN Documentation of the show cachestate command更多细节。您可以通过执行该过程并解析文本结果将其转换为“API”。

    大警告:我从未见过这个命令行应用程序实际上在我的服务器上返回任何内容,即使是在经典模式下运行的应用程序也是如此。不知道为什么——但正如我从其他在线帖子中看到的那样,该应用程序确实有效。 (例如 http://chrison.net/ViewingTheKernelCache.aspx )

    如果您对进程创建极度过敏并感到雄心勃勃,NETSH 命令由带有文档的 Win32 接口(interface)的 DLL 实现,因此您可以编写伪装成 NETSH.exe 的代码并直接调用 IIS 的 NETSH 帮助程序 DLL。您可以使用 documentation on MSDN作为这种方法的起点。警告:模拟 NETSH 非常困难,因为接口(interface)是 2 路的:NETSH 调用 DLL,DLL 调用回 NETSH。而且您仍然必须解析文本输出,因为 NETSH 接口(interface)是基于文本的,而不是像 PowerShell 或 WMI 那样基于对象的。如果是我,我只会生成一个 NETSH 进程。 ;-)

    IIS7 PowerShell snapin 可能将来可能会支持此功能(这意味着比上述黑客更容易编程访问),但今天只有 AFAIK NETSH 支持此功能。

    失效:

    我有好消息和坏消息要告诉你。

    好消息:一旦您知道要从 IIS 的内核缓存中提取的项目的 URL,就有一个 Win32 API 可用于在 IIS6 及更高版本上将其删除。这可以通过 P/Invoke(更难)从 C# 调用,或者通过将调用放在托管 C++ 包装 DLL 中。见 HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK在 MSDN 上了解详细信息。

    我尝试了所需的代码(附在下面)。警告:它丑陋且未经测试——它不会使我的 IIS 崩溃,但(见上文)我无法弄清楚如何让缓存枚举工作,因此我实际上无法使用有效的 URL 调用它以从缓存中提取。如果您可以使枚​​举工作,那么插入一个有效的 URL(并因此测试此代码)应该很容易。

    坏消息:
  • 正如你可以从代码示例中猜到的那样,它不能在 IIS7 的集成管道模式下工作,只能在 ASP.NET 作为 ISAPI 运行并可以访问 ISAPI 函数的经典模式(当然是 IIS6)下工作
  • 弄乱私有(private)字段是一个大技巧,可能会在新版本中中断
  • P/Invoke 很难处理,需要(我相信)完全信任

  • 这是一些代码:
    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");
            }
        }
    }
    

    关于asp.net - 有什么方法可以从 ASP.NET 访问 IIS 内核缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1276155/

    相关文章:

    c# - Web API 项目中 CreateHostBuilder 中的 Lambda 表达式

    c# - 将工作时间换算为 24 小时的代码?

    asp.net - 如何禁用表单例份验证

    mysql - 清除 MySQL 查询缓存而不重新启动服务器

    c - 2way缓存关联?我从内存中读取了多少字节?

    asp.net - 我在使用asp.net core 2.2应用程序的生产上的facebook登录回调中收到错误500

    iis-7 - 删除 "OPTIONSVerbHandler"和 "TRACEVerbHandler"会杀死 iis 上的网站吗?

    iis - 如何使用 appcmd.exe 显示 Web 应用程序的物理路径?

    asp.net-mvc-3 - 具有有效 URL 的 ASP.NET MVC "Potentially dangerous Request.Path"

    java - 订购 map 逻辑