2009-08-14 9 views
6

ta kasuje tylko elementy w pamięci podręcznej użytkownika:Dowolny sposób uzyskiwania dostępu do pamięci podręcznej jądra IIS z programu ASP.NET?

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

Czy istnieje jakiś sposób, aby uzyskać dostęp do pamięci podręcznej jądra, jak również?

Wyjaśnienie: Chcę drukować klucze wszystkich elementów w pamięci podręcznej jądra, a jako bonus Chciałbym móc wyczyścić pamięć podręczną jądra z metody C#, jak również.

+1

Istnieje dalsza dyskusja na temat tego problemu tutaj: http://www.west-wind.com/weblog/posts/11379.aspx#121596 (patrz komentarze). Czy ktoś ma lepsze rozwiązanie niż to, co jest tam wspomniane? –

Odpowiedz

11

Tak, można programowo wyliczyć i usunąć elementy z pamięci podręcznej jądra IIS.

Ostrzeżenia:

  • nietrywialne parsowanie tekstu requred dla wyliczenia
  • wiele brzydkich P/Invoke wymagane do usuwania
  • Ponadto, trzeba co najmniej średnie Trust (i zapewne pełne zaufanie) robić rzeczy poniżej.
  • Usunięcie nie działa w zintegrowanym trybie potoku usług IIS.
  • Wyliczanie prawdopodobnie nie będzie działać na IIS6

liczby:

Jedyny sposób udokumentowane wiem wyliczyć cache jądra IIS to aplikacja wiersza poleceń dostępnych w IIS7 i powyżej (chociaż możesz być w stanie skopiować bibliotekę DLL pomocnika NETSH z V7 na system V6 - nie próbowałem go).

netsh http show cachestate 

Aby uzyskać więcej informacji, zobacz MSDN Documentation of the show cachestate command. Możesz przekształcić to w "API", wykonując proces i analizując wyniki tekstowe.

Big Zastrzeżenie: Nigdy nie widziałem tej aplikacji wiersza polecenia faktycznie powrócić coś na moim serwerze, nawet dla aplikacji działających w trybie Classic. Nie wiem, dlaczego - ale aplikacja działa tak, jak widzę z innych wpisów online. (Np http://chrison.net/ViewingTheKernelCache.aspx)

Jeśli jesteś strasznie uczulony na proces tworzenia i uczucie ambitne netsh polecenia są realizowane przez DLL z udokumentowanym interfejs Win32, więc można napisać kod, który udaje, że to netsh.exe i stawia pod NETSH pomocnika IIS DLL bezpośrednio. Możesz użyć documentation on MSDN jako punktu wyjścia dla tego podejścia. Ostrzeżenie: podszywanie się pod NETSH jest nietrywialne, ponieważ interfejs jest dwukierunkowy: wywołania NETSH do biblioteki DLL i wywołanie DLL z powrotem do NETSH. I nadal będziesz musiał przeanalizować wynik tekstowy, ponieważ interfejs NETSH jest oparty na tekście, a nie na obiektach takich jak PowerShell lub WMI. Gdyby to był ja, zamiast tego odrodziłem proces NETSH. ;-)

Jest możliwe, że IIS7 PowerShell snapin może obsługiwać tę funkcję w przyszłości (co oznacza łatwiejszy dostęp programistyczny niż powyższe hacki), ale tylko AFAIK NETSH obsługuje tę funkcję już dziś.

Unieważnienie:

Mam dobrą i złą wiadomość dla ciebie.

Dobra wiadomość: gdy poznasz adres URL przedmiotu, który chcesz przeciągnąć z pamięci podręcznej jądra IIS, dostępny jest interfejs Win32 API do usunięcia go w usługach IIS6 i nowszych. Można to wywołać z C# poprzez P/Invoke (trudniejsze) lub przez umieszczenie wywołania w zarządzanej bibliotece DLL C++. Szczegółowe informacje można znaleźć na stronie MSDN pod numerem HSE_REQ_GET_CACHE_INVALIDATION_CALLBACK.

Wziąłem ukłucie przy wymaganym kodzie (załączonym poniżej). Ostrzeżenie: jest brzydki i nieprzetestowany - nie psuje mojego IIS, ale (patrz wyżej) Nie mogę wymyślić, jak uruchomić wyliczanie pamięci podręcznej, więc nie mogę go wywołać z poprawnym adresem URL, aby pobrać z pamięci podręcznej. Jeśli możesz sprawić, by wyliczenie działało, wtedy podłączenie poprawnego adresu URL (i przetestowanie tego kodu) powinno być łatwe.

Zła wiadomość:

  • jak można się domyślić z próbki kodu, to nie będzie działać w trybie zintegrowanym rurociągu IIS7 jest tylko w trybie Classic (lub IIS6, oczywiście) gdzie przebiega ASP.NET jako ISAPI i ma dostęp do funkcji ISAPI
  • brudząc z pól prywatnych jest duża siekać i może pęknąć w nowej wersji
  • P/Invoke jest trudne do zniesienia i wymaga (wierzę) pełne zaufanie

Oto kod:

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"); 
     } 
    } 
} 
+0

Świetna odpowiedź! Dziękuję Ci. –

0

Z podanego łącza do dyskusji wynika, że ​​metoda lub właściwość pamięci podręcznej istnieje, ale jest chroniona lub prywatna, więc nie można uzyskać do niej dostępu.

Normalnie, należy trzymać z dala od użyciu metod, które nie są częścią publicznych API, ale jeśli chcesz mieć do nich dostęp, korzystanie refleksji. Dzięki refleksji możesz wywoływać prywatne metody i uzyskiwać lub ustawiać prywatne właściwości i pola.

Powiązane problemy