C# CookieContainer bug?
我不知道CookieContainer是如何处理域的,所以我创建了这个测试。 此测试显示cookieContainer不会返回“example.com”的任何cookie,但根据RFC,它应该返回至少2个cookie 这不是一只虫子吗 如何使它工作 以下是有关此错误的讨论:C# CookieContainer bug?,c#,cookiecontainer,C#,Cookiecontainer,我不知道CookieContainer是如何处理域的,所以我创建了这个测试。 此测试显示cookieContainer不会返回“example.com”的任何cookie,但根据RFC,它应该返回至少2个cookie 这不是一只虫子吗 如何使它工作 以下是有关此错误的讨论: CookieContainer getContainer() { CookieContainer结果=新建CookieContainer(); Uri=新的Uri(“http://sub.example.com"); 字
CookieContainer getContainer()
{
CookieContainer结果=新建CookieContainer();
Uri=新的Uri(“http://sub.example.com");
字符串cookieH=@“Test1=val;domain=sub.example.com;path=/”;
结果:SetCookies(uri,cookieH);
cookieH=@“Test2=val;domain=.example.com;path=/”;
结果:SetCookies(uri,cookieH);
cookieH=@“Test3=val;domain=example.com;path=/”;
结果:SetCookies(uri,cookieH);
返回结果;
}
无效测试()
{
CookieContainer cookie=getContainer();
lblResult.Text+=“
cookies总数:”+cookie.count+“预期为3”;
Uri=新的Uri(“http://sub.example.com");
CookieCollection coll=cookie.GetCookies(uri);
lblResult.Text+=“+uri+”Cookie计数的“
”:“+coll.count+”应为:2”;
uri=新的uri(“http://other.example.com");
coll=cookie.GetCookies(uri);
lblResult.Text+=“+uri+”Cookie计数的“
”:“+coll.count+”应为:2”;
uri=新的uri(“http://example.com");
coll=cookie.GetCookies(uri);
lblResult.Text+=“+uri+”Cookie计数的“
”:“+coll.count+”应为:2”;
}
受保护的无效页面加载(对象发送方、事件参数e)
{
Test();
}
CookieContainer测试页面
以下是一个绕过此错误的方法:
它使用反射。最后他们将修复它:
我刚刚找到了此错误的修复方法,并在此处进行了讨论: 以下是解决方案:
private void BugFix_CookieDomain(CookieContainer cookieContainer)
{
System.Type _ContainerType = typeof(CookieContainer);
Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.GetField |
System.Reflection.BindingFlags.Instance,
null,
cookieContainer,
new object[] { });
ArrayList keys = new ArrayList(table.Keys);
foreach (string keyObj in keys)
{
string key = (keyObj as string);
if (key[0] == '.')
{
string newKey = key.Remove(0, 1);
table[newKey] = table[keyObj];
}
}
}
在这个问题上我失去了一天。CallMeLaNN的回答对我没有帮助(我正在使用.NET4.5)。在我的例子中,问题在于设置请求主体和设置cookie的顺序 在这种情况下,Cookie将不会发送到服务器:
var response = (HttpWebRequest)WebRequest.Create("http://localhost:4433/");
using (var requestStream = response.GetRequestStream())
{
using (var streamWriter = new StreamWriter(requestStream))
{
requestStream.Write(RequestContent);
}
}
response.CookieContainer.Add(new Cookie("Name", "Value"));
await response.GetResponseAsync();
要使其正常工作,需要更改订单:
var response = (HttpWebRequest)WebRequest.Create("http://localhost:4433/");
response.CookieContainer.Add(new Cookie("Name", "Value"));
await response.GetResponseAsync();
using (var requestStream = response.GetRequestStream())
{
using (var streamWriter = new StreamWriter(requestStream))
{
requestStream.Write(RequestContent);
}
}
我已经为这个问题创建了一个修复程序,可以在Windows 10/UWP/.NET核心应用程序上运行。问题在于
CookieContainer
的内部结构不同,但与.NET框架中的内部结构一样糟糕。因此,公认的解决方案不再有效
但是,我没有“修复”CookieContainer,而是编写了一个版本的GetCookies()
,它用一个字符串获取特定域的所有Cookie,而不管它们的“安全”状态如何,或者它们是否以点为前缀。您可以根据自己的需要随意修改它,我将考虑在未来的.NET核心版本中实现它的一个版本
using System.Collections.Generic;
using System.Reflection;
namespace System.Net
{
/// <summary>
/// Contains extensions for the <see cref="CookieContaner"/> class.
/// </summary>
public static class CookieContainerExtensions
{
/// <summary>
/// Uses Reflection to get ALL of the <see cref="Cookie">Cookies</see> where <see cref="Cookie.Domain"/>
/// contains part of the specified string. Will return cookies for any subdomain, as well as dotted-prefix cookies.
/// </summary>
/// <param name="cookieContainer">The <see cref="CookieContainer"/> to extract the <see cref="Cookie">Cookies</see> from.</param>
/// <param name="domain">The string that contains part of the domain you want to extract cookies for.</param>
/// <returns></returns>
public static IEnumerable<Cookie> GetCookies(this CookieContainer cookieContainer, string domain)
{
var domainTable = GetFieldValue<dynamic>(cookieContainer, "_domainTable");
foreach (var entry in domainTable)
{
string key = GetPropertyValue<string>(entry, "Key");
if (key.Contains(domain))
{
var value = GetPropertyValue<dynamic>(entry, "Value");
var internalList = GetFieldValue<SortedList<string, CookieCollection>>(value, "_list");
foreach (var li in internalList)
{
foreach (Cookie cookie in li.Value)
{
yield return cookie;
}
}
}
}
}
/// <summary>
/// Gets the value of a Field for a given object instance.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> you want the value to be converted to when returned.</typeparam>
/// <param name="instance">The Type instance to extract the Field's data from.</param>
/// <param name="fieldName">The name of the Field to extract the data from.</param>
/// <returns></returns>
internal static T GetFieldValue<T>(object instance, string fieldName)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo fi = instance.GetType().GetField(fieldName, bindFlags);
return (T)fi.GetValue(instance);
}
/// <summary>
/// Gets the value of a Property for a given object instance.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> you want the value to be converted to when returned.</typeparam>
/// <param name="instance">The Type instance to extract the Property's data from.</param>
/// <param name="propertyName">The name of the Property to extract the data from.</param>
/// <returns></returns>
internal static T GetPropertyValue<T>(object instance, string propertyName)
{
var pi = instance.GetType().GetProperty(propertyName);
return (T)pi.GetValue(instance, null);
}
}
}
使用System.Collections.Generic;
运用系统反思;
命名空间系统.Net
{
///
///包含类的扩展。
///
公共静态类CookieContaineExtensions
{
///
///使用反射获取所有cookie,其中
///包含指定字符串的一部分。将返回任何子域的Cookie以及虚线前缀Cookie。
///
///要从中提取Cookies的。
///包含要为其提取Cookie的域的一部分的字符串。
///
公共静态IEnumerable GetCookies(此CookieContainer CookieContainer,字符串域)
{
var domainTable=GetFieldValue(cookieContainer,“\u domainTable”);
foreach(域中的var条目)
{
字符串键=GetPropertyValue(输入,“键”);
if(key.Contains(域))
{
var值=GetPropertyValue(输入,“值”);
var internalList=GetFieldValue(值“_list”);
foreach(内部列表中的var li)
{
foreach(li.Value中的Cookie)
{
收益率;
}
}
}
}
}
///
///获取给定对象实例的字段值。
///
///返回时要将值转换为的值。
///要从中提取字段数据的类型实例。
///要从中提取数据的字段的名称。
///
内部静态T GetFieldValue(对象实例,字符串fieldName)
{
BindingFlags bindFlags=BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo fi=instance.GetType().GetField(fieldName,bindFlags);
返回(T)fi.GetValue(实例);
}
///
///获取给定对象实例的属性值。
///
///返回时要将值转换为的值。
///要从中提取属性数据的类型实例。
///要从中提取数据的属性的名称。
///
内部静态T GetPropertyValue(对象实例,字符串propertyName)
{
var pi=instance.GetType().GetProperty(propertyName);
返回(T)pi.GetValue(实例,null);
}
}
}
我以前也尝试过很多次。最后我自己读取了cookie头并将其存储在其他地方。我必须使用CookieContainer,因为这是将cookie发送到HttpWebRequest的唯一方法。真不敢相信我最终出现了一个场景,将框架从4.0更改为3.5(我没有使用4.0的东西)破坏了我的程序。我是这么想的
var response = (HttpWebRequest)WebRequest.Create("http://localhost:4433/");
response.CookieContainer.Add(new Cookie("Name", "Value"));
await response.GetResponseAsync();
using (var requestStream = response.GetRequestStream())
{
using (var streamWriter = new StreamWriter(requestStream))
{
requestStream.Write(RequestContent);
}
}
using System.Collections.Generic;
using System.Reflection;
namespace System.Net
{
/// <summary>
/// Contains extensions for the <see cref="CookieContaner"/> class.
/// </summary>
public static class CookieContainerExtensions
{
/// <summary>
/// Uses Reflection to get ALL of the <see cref="Cookie">Cookies</see> where <see cref="Cookie.Domain"/>
/// contains part of the specified string. Will return cookies for any subdomain, as well as dotted-prefix cookies.
/// </summary>
/// <param name="cookieContainer">The <see cref="CookieContainer"/> to extract the <see cref="Cookie">Cookies</see> from.</param>
/// <param name="domain">The string that contains part of the domain you want to extract cookies for.</param>
/// <returns></returns>
public static IEnumerable<Cookie> GetCookies(this CookieContainer cookieContainer, string domain)
{
var domainTable = GetFieldValue<dynamic>(cookieContainer, "_domainTable");
foreach (var entry in domainTable)
{
string key = GetPropertyValue<string>(entry, "Key");
if (key.Contains(domain))
{
var value = GetPropertyValue<dynamic>(entry, "Value");
var internalList = GetFieldValue<SortedList<string, CookieCollection>>(value, "_list");
foreach (var li in internalList)
{
foreach (Cookie cookie in li.Value)
{
yield return cookie;
}
}
}
}
}
/// <summary>
/// Gets the value of a Field for a given object instance.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> you want the value to be converted to when returned.</typeparam>
/// <param name="instance">The Type instance to extract the Field's data from.</param>
/// <param name="fieldName">The name of the Field to extract the data from.</param>
/// <returns></returns>
internal static T GetFieldValue<T>(object instance, string fieldName)
{
BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
FieldInfo fi = instance.GetType().GetField(fieldName, bindFlags);
return (T)fi.GetValue(instance);
}
/// <summary>
/// Gets the value of a Property for a given object instance.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> you want the value to be converted to when returned.</typeparam>
/// <param name="instance">The Type instance to extract the Property's data from.</param>
/// <param name="propertyName">The name of the Property to extract the data from.</param>
/// <returns></returns>
internal static T GetPropertyValue<T>(object instance, string propertyName)
{
var pi = instance.GetType().GetProperty(propertyName);
return (T)pi.GetValue(instance, null);
}
}
}