2013-04-13 20 views
16

Voglio esportare un CookieContainer a JSON utilizzando Newtonsoft.Json ma purtroppo CookieContainer non ha un enumeratore o roba, quindi non posso scorrere esso ...Come posso ottenere tutti i cookie di un CookieContainer?

Edit: Con la mia soluzione postato sarebbe essere qualcosa di simile:

private static void Main(string[] args) 
{ 
    CookieContainer cookieContainer = new CookieContainer(); 
    cookieContainer.Add(new Cookie("name1", "value1", "/", ".testdomain1.com")); 
    cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".testdomain1.com")); 
    cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".testdomain1.com")); 
    cookieContainer.Add(new Cookie("name1", "value1", "/", ".testdomain2.com")); 
    cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".testdomain2.com")); 
    cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".testdomain2.com")); 

    CookieCollection cookies = GetAllCookies(cookieContainer); 

    Console.WriteLine(JsonConvert.SerializeObject(cookies, Formatting.Indented)); 
    Console.Read(); 
} 
+1

Non penso che ci sia un modo per ottenere tutti i cookie oltre all'utilizzo di reflection per accedere ai campi privati ​​di CookieContainer (non lo consiglio). Dovresti semplicemente archiviare i cookie separatamente e metterli in un CookieContainer quando è necessario. – Will

risposta

15

una soluzione utilizzando la riflessione:

public static CookieCollection GetAllCookies(CookieContainer cookieJar) 
{ 
    CookieCollection cookieCollection = new CookieCollection(); 

    Hashtable table = (Hashtable) cookieJar.GetType().InvokeMember("m_domainTable", 
                    BindingFlags.NonPublic | 
                    BindingFlags.GetField | 
                    BindingFlags.Instance, 
                    null, 
                    cookieJar, 
                    new object[] {}); 

    foreach (var tableKey in table.Keys) 
    { 
     String str_tableKey = (string) tableKey; 

     if (str_tableKey[0] == '.') 
     { 
      str_tableKey = str_tableKey.Substring(1); 
     } 

     SortedList list = (SortedList) table[tableKey].GetType().InvokeMember("m_list", 
                    BindingFlags.NonPublic | 
                    BindingFlags.GetField | 
                    BindingFlags.Instance, 
                    null, 
                    table[tableKey], 
                    new object[] { }); 

     foreach (var listKey in list.Keys) 
     { 
      String url = "https://" + str_tableKey + (string) listKey; 
      cookieCollection.Add(cookieJar.GetCookies(new Uri(url))); 
     } 
    } 

    return cookieCollection; 
} 
+0

Questo codice stampa solo i cookie https e ignora http. Versione migliorata qui: http://stackoverflow.com/a/36665793/2010764 –

+0

Sto usando questo metodo su un sito Web http. Funziona bene e restituisce tutti i cookie http. Ma quando cambio https su http non stampa tutti i cookie, solo quelli che sono sul dominio principale. – Milad

6

La prima risposta non ha funzionato per un progetto portatile. Quindi, ecco l'opzione 2, utilizza anche riflessione

using System.Linq; 
using System.Collections; 
using System.Reflection; 
using System.Net; 

    public static CookieCollection GetAllCookies(this CookieContainer container) 
    { 
     var allCookies = new CookieCollection(); 
     var domainTableField = container.GetType().GetRuntimeFields().FirstOrDefault(x => x.Name == "m_domainTable");    
     var domains = (IDictionary)domainTableField.GetValue(container); 

     foreach (var val in domains.Values) 
     { 
      var type = val.GetType().GetRuntimeFields().First(x => x.Name == "m_list"); 
      var values = (IDictionary)type.GetValue(val); 
      foreach (CookieCollection cookies in values.Values) 
      { 
       allCookies.Add(cookies);      
      } 
     }   
     return allCookies; 
    } 

1) Ho anche provato

var domainTableField = container.GetType().GetRuntimeField("m_domainTable"); 

ma restituito NULL.

2) È possibile scorrere tra i domini. Chiavi e utilizzare container.GetCookies() per tutte le chiavi. Ma ho avuto problemi con questo, perché GetCookies si aspetta che Uri e non tutte le mie chiavi corrispondano al modello di Uri.

4

Questo metodo farà in modo di ottenere tutti i cookie, non importa quale sia il protocollo è:

public static IEnumerable<Cookie> GetAllCookies(this CookieContainer c) 
{ 
    Hashtable k = (Hashtable)c.GetType().GetField("m_domainTable", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(c); 
    foreach (DictionaryEntry element in k) 
    { 
     SortedList l = (SortedList)element.Value.GetType().GetField("m_list", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(element.Value); 
     foreach (var e in l) 
     { 
      var cl = (CookieCollection)((DictionaryEntry)e).Value; 
      foreach (Cookie fc in cl) 
      { 
       yield return fc; 
      } 
     } 
    } 
} 
0

Usa CookieContainer.GetCookies Method

CookieCollection cookies = cookieContainer.GetCookies(new Uri(url)); 

dove url è URL del vostro sito.

Nel mio caso, non sono stato in grado di utilizzare il riflesso, come suggerito in altre risposte. Tuttavia, conoscevo l'URL del mio sito da interrogare. Penso che sia logico che il contenitore non restituisca tutti i cookie alla cieca, ma li restituisca per URL perché i cookie appartengono sempre a un particolare URL e non possono essere utilizzati al di fuori del contesto del dominio ad essi associato.

+0

Non sono sicuro del motivo per cui altri autori necessitavano di riflessione e codice speciale. –

Problemi correlati