请参阅下面的代码:
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;
如何在cookieJar
内获取 cookie 信息?(所有这些,而不仅仅是针对特定域。
我怎样才能从中添加或删除饼干?
没有一个答案对我有用。这是我对这个问题的谦虚解决方案。
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;
}
反射可用于获取保存 CookieContainer 对象中所有域键的私有字段,
问。我如何获得该私有字段的名称?
答:使用反射器;
其声明为:
private Hashtable m_domainTable;
一旦我们获得了私有字段,我们将获得域密钥,然后获取cookie是一个简单的迭代。
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();
}
}
}
感谢 AppDeveloper 的回答,这里有一个稍微修改的版本作为扩展方法。
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;
}
}
要获取列表,只需在 CookieContainer 上调用 List():
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();
PaRiMal RaJ代码的改进版本。此方法将同时打印 http 和 https cookie。准备将其粘贴到您的课堂中。
// 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);
}
}
这是一个扩展,它将antfx的代码与Adrian Lopez同时使用http和https的想法相结合。对于可能发现它有用的任何人来说,这只是一个快速解决方案:
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;
}
}
如果你要编写一个nUnit测试,它将是这样的:
[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);
}
}
}
据我所知,这里提供的所有解决方案都忽略了cookie域路径可能与通常的"/"不同的事实。如果是这种情况,uri 提取字符串。格式("http://{0}/", 域);或字符串。格式("https://{0}/", 域);将失败。那是因为实际上它应该是字符串。格式("http://{0}/{1}/", 域, 路径);那么问题是如何从 cookiecontainer 获取该路径值。
我使用了一种不同的方法,直接从cookie容器的非公共成员中提取cookie(在cookie集合中)。
/// <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);
}
}
}
}