20

Please see the code below:

CookieContainer cookieJar = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com");
request.CookieContainer = cookieJar;

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
int cookieCount = cookieJar.Count;

How can I get cookies info inside cookieJar? (All of them, not just for a specific domain.)
And how can I add or remove a cookie from that?

Sam
  • 7,252
  • 16
  • 46
  • 65
SilverLight
  • 19,668
  • 65
  • 192
  • 300
  • Finally, .NET 6 introduced the `CookieContainer.GetAllCookies()` - [Documentation link](https://learn.microsoft.com/en-us/dotnet/api/system.net.cookiecontainer.getallcookies?view=net-6.0). – aepot Nov 09 '21 at 19:44

7 Answers7

20

None of the answers worked for me. This is my humble solution for the problem.

public static List<Cookie> List(this CookieContainer container)
{
    var cookies = new List<Cookie>();

    var table = (Hashtable)container.GetType().InvokeMember("m_domainTable",
        BindingFlags.NonPublic |
        BindingFlags.GetField |
        BindingFlags.Instance,
        null,
        container,
        null);

    foreach (string key in table.Keys)
    {
        var item = table[key];
        var items = (ICollection) item.GetType().GetProperty("Values").GetGetMethod().Invoke(item, null);
        foreach (CookieCollection cc in items)
        {
            foreach (Cookie cookie in cc)
            {
                cookies.Add(cookie);
            }
        }
    }

    return cookies;
}           
JJS
  • 6,431
  • 1
  • 54
  • 70
16

reflection can be used to get the private field that holds all the domain key in CookieContainer object,

Q. How do i got the name of that private field ?

Ans. Using Reflector;

its is declared as :

private Hashtable m_domainTable;

once we get the private field, we will get the the domain key, then getting cookies is a simple iteration.

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

namespace ConsoleApplication4
{
    static class Program
    {
        private static void Main()
        {
            CookieContainer cookies = new CookieContainer();
            cookies.Add(new Cookie("name1", "value1", "/", "domain1.com"));
            cookies.Add(new Cookie("name2", "value2", "/", "domain2.com"));

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

            foreach (var key in table.Keys)
            {
                Uri uri = new Uri(string.Format("http://{0}/", key));

                foreach (Cookie cookie in cookies.GetCookies(uri))
                {
                    Console.WriteLine("Name = {0} ; Value = {1} ; Domain = {2}",
                        cookie.Name, cookie.Value, cookie.Domain);
                }
            }

            Console.Read();
        }
    }
}
shmnff
  • 647
  • 2
  • 15
  • 31
Parimal Raj
  • 20,189
  • 9
  • 73
  • 110
  • This method seems to assume http protocol and cookies created for https will not be shown. – user1713059 Oct 29 '14 at 11:08
  • @user1713059 - where does it shows that it is doing this only for HTTP ? anyways, this will get cookies for both http + https. – Parimal Raj Oct 29 '14 at 13:59
  • There is a `string.Format("http://` in the console print loop. The `GetCookies` method is called using domain names prefixed with http only. – user1713059 Nov 05 '14 at 12:02
  • > how do you get the name? From the source, where else? https://referencesource.microsoft.com/#System/net/System/Net/cookiecontainer.cs,eb89f175de026fb3 – JJS Jan 04 '19 at 20:27
7

Thank's to AppDeveloper for their answer, here is a slightly modified version as an extension method.

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

public static class CookieContainerExtension
{
    public static List<Cookie> List(this CookieContainer container)
    {
        var cookies = new List<Cookie>();

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

        foreach (var key in table.Keys)
        {

            Uri uri = null;

            var domain = key as string;

            if (domain == null)
                continue;

            if (domain.StartsWith("."))
                domain = domain.Substring(1);

            var address = string.Format("http://{0}/", domain);

            if (Uri.TryCreate(address, UriKind.RelativeOrAbsolute, out uri) == false)
                continue;

            foreach (Cookie cookie in container.GetCookies(uri))
            {
                cookies.Add(cookie);
            }
        }

        return cookies;
    }
}

To get the list just call List() on the CookieContainer:

CookieContainer cookies = new CookieContainer();
cookies.Add(new Cookie("name1", "value1", "/", "www.domain1.com"));
cookies.Add(new Cookie("name2", "value2", "/", "www.domain2.com"));
List<Cookie> cookieList = cookies.List();
antfx
  • 3,205
  • 3
  • 35
  • 45
6

Improved version of PaRiMal RaJ's code. This method will print both, http and https cookies. Ready to paste it in your class.

    // Paste this dependencies in your class
    using System;
    using System.Net;
    using System.Linq;
    using System.Reflection;
    using System.Collections;
    using System.Collections.Generic;

    /// <summary>
    /// It prints all cookies in a CookieContainer. Only for testing.
    /// </summary>
    /// <param name="cookieJar">A cookie container</param>
    public void PrintCookies (CookieContainer cookieJar)
    {
        try
        {
            Hashtable table = (Hashtable) cookieJar
                .GetType().InvokeMember("m_domainTable",
                BindingFlags.NonPublic |
                BindingFlags.GetField |
                BindingFlags.Instance,
                null,
                cookieJar,
                new object[] {});


            foreach (var key in table.Keys)
            {
                // Look for http cookies.
                if (cookieJar.GetCookies(
                    new Uri(string.Format("http://{0}/", key))).Count > 0)
                {
                    Console.WriteLine(cookieJar.Count+" HTTP COOKIES FOUND:");
                    Console.WriteLine("----------------------------------");
                    foreach (Cookie cookie in cookieJar.GetCookies(
                        new Uri(string.Format("http://{0}/", key))))
                    {
                        Console.WriteLine(
                            "Name = {0} ; Value = {1} ; Domain = {2}", 
                            cookie.Name, cookie.Value,cookie.Domain);
                    }
                }

                // Look for https cookies
                if (cookieJar.GetCookies(
                    new Uri(string.Format("https://{0}/", key))).Count > 0)
                {
                    Console.WriteLine(cookieJar.Count+" HTTPS COOKIES FOUND:");
                    Console.WriteLine("----------------------------------");
                    foreach (Cookie cookie in cookieJar.GetCookies(
                        new Uri(string.Format("https://{0}/", key))))
                    {
                        Console.WriteLine(
                            "Name = {0} ; Value = {1} ; Domain = {2}", 
                            cookie.Name, cookie.Value,cookie.Domain);
                    }
                }
            }
        }
        catch(Exception e)
        {
            Console.WriteLine (e);
        }
    }
Adrian Lopez
  • 2,601
  • 5
  • 31
  • 48
  • 1
    Thanks your code works, but I sometimes get UriFormatException errors. Any suggestions as to how to get those cookies to print out? – Gaspare Bonventre Jan 10 '17 at 21:02
  • From what I understand...there's no reason to have separate code for pulling HTTPS and HTTP cookies. If you use an HTTPS Uri, GetCookies() will return both. It will also return duplicates if there are domains without a sub-domain. Such as www.example.com and example.com. If you pass in www.example.com it will return all cookies that also match example.com – Chad Baldwin Oct 06 '20 at 15:33
4

Here's an Extension that combines antfx's code with Adrian Lopez's idea of using both http and https. Just a quick fix for anyone who might find it useful:

public static class CookieContainerExtensions
{
    public static List<Cookie> List(this CookieContainer container)
    {
        var cookies = new List<Cookie>();

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

        foreach (var key in table.Keys)
        {
            var domain = key as string;

            if (domain == null)
                continue;

            if (domain.StartsWith("."))
                domain = domain.Substring(1);

            var httpAddress = string.Format("http://{0}/", domain);
            var httpsAddress = string.Format("https://{0}/", domain);

            if (Uri.TryCreate(httpAddress, UriKind.RelativeOrAbsolute, out var httpUri))
            {
                foreach (Cookie cookie in container.GetCookies(httpUri))
                {
                    cookies.Add(cookie);
                }
            }
            if (Uri.TryCreate(httpsAddress, UriKind.RelativeOrAbsolute, out var httpsUri))
            {
                foreach (Cookie cookie in container.GetCookies(httpsUri))
                {
                    cookies.Add(cookie);
                }
            }
        }

        return cookies;
    }
}
Daniel Ecker
  • 105
  • 13
1

If you were to write a nUnit test, it would be something like this:

    [Test]
    public void Test()
    {

        CookieContainer cookies = new CookieContainer();
        cookies.Add(new Cookie("name1", "value1", "/", "www.domain1.com"));
        cookies.Add(new Cookie("name2", "value2", "/", "www.domain2.com"));

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



        foreach (var key in table.Keys)
        {
            foreach (Cookie cookie in cookies.GetCookies(new Uri(string.Format("http://{0}/", key.ToString().Substring(1,key.ToString().Length - 1)))))
            {
                Assert.That(cookie != null);
                //Console.WriteLine("Name = {0} ; Value = {1} ; Domain = {2}", cookie.Name, cookie.Value,
                //                  cookie.Domain);
            }
        }



    }
Rafael Fernandes
  • 505
  • 6
  • 10
1

As far as I could figure it out, all of the solutions provided here ignore the fact that the cookie domain path can be different than the usual "/". If that is the case the uri extraction string.Format("http://{0}/", domain); or string.Format("https://{0}/", domain); will fail. That is because in fact it should be string.Format("http://{0}/{1}/", domain, path); The problem then is how to get that path value from the cookiecontainer .

I used a different approach that directly extracts cookies (in a cookie collection) from the non public members of the cookiecontainer.

/// <summary>
/// Extracts the cookiecollection from a cookiecontainer
/// This also works when the domain path is not the standard /
/// (Unlike most or all the solutions found in the public domain that recover the uri from the domain value
/// ignoring the path )
/// It directly extracts the cookie collections from 'non public' members of the cookiecontainer class
/// </summary>
/// <param name="container"></param>
/// <param name="collection"></param>
private void ExtractCookies (CookieContainer container, out CookieCollection collection)
{
    collection = new ();

    var table = (Hashtable)container.GetType().InvokeMember("m_domainTable",
    BindingFlags.NonPublic |
    BindingFlags.GetField |
    BindingFlags.Instance,
    null,
    container,
    null);

    foreach (string key in table.Keys)
    {
        var item = table[key];

        SortedList slcc = (SortedList)item.GetType().InvokeMember("m_list",
        BindingFlags.NonPublic |
        BindingFlags.GetField |
        BindingFlags.Instance,
        null,
        item,
        null);

        if (slcc != null)
        {
            foreach (DictionaryEntry dcc in slcc)
            {
                string path = dcc.Key.ToString(); // the domain path, not used
                CookieCollection cc = (CookieCollection)dcc.Value;
                collection.Add(cc);
            }
        }
    }
}
WGmaker
  • 21
  • 3