2009-06-26 12 views
16

Ich bin verwirrt, wie CookieContainer Domain behandelt, also erstelle ich diesen Test. Dieser Test zeigt, dass cookieContainer kein Cookie für "example.com" zurückgibt, aber gemäß RFC mindestens 2 Cookies zurückgeben soll.CookieContainer Bug?

Ist es nicht ein Fehler?

Wie funktioniert es? Hier

ist eine Diskussion über diesen Fehler:

http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/c4edc965-2dc2-4724-8f08-68815cf1dce6

<%@ Page Language="C#" %> 

<%@ Import Namespace="System.Net" %> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<script runat="server"> 
    CookieContainer getContainer() 
    { 
     CookieContainer result = new CookieContainer(); 

     Uri uri = new Uri("http://sub.example.com"); 
     string cookieH = @"Test1=val; domain=sub.example.com; path=/"; 
     result.SetCookies(uri, cookieH); 

     cookieH = @"Test2=val; domain=.example.com; path=/"; 
     result.SetCookies(uri, cookieH); 

     cookieH = @"Test3=val; domain=example.com; path=/"; 
     result.SetCookies(uri, cookieH); 

     return result; 
    } 

    void Test() 
    { 
     CookieContainer cookie = getContainer(); 
     lblResult.Text += "<br>Total cookies count: " + cookie.Count + " &nbsp;&nbsp; expected: 3"; 

     Uri uri = new Uri("http://sub.example.com"); 
     CookieCollection coll = cookie.GetCookies(uri); 
     lblResult.Text += "<br>For " + uri + " Cookie count: " + coll.Count + " &nbsp;&nbsp; expected: 2"; 

     uri = new Uri("http://other.example.com"); 
     coll = cookie.GetCookies(uri); 
     lblResult.Text += "<br>For " + uri + " Cookie count: " + coll.Count + " &nbsp;&nbsp; expected: 2"; 

     uri = new Uri("http://example.com"); 
     coll = cookie.GetCookies(uri); 
     lblResult.Text += "<br>For " + uri + " Cookie count: " + coll.Count + " &nbsp;&nbsp; expected: 2"; 

    } 

    protected void Page_Load(object sender, EventArgs e) 
    { 
     Test(); 
    } 
</script> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title>CookieContainer Test Page</title> 
</head> 
<body> 
    <form id="frmTest" runat="server"> 
    <asp:Label ID="lblResult" EnableViewState="false" runat="server"></asp:Label> 
    </form> 
</body> 
</html> 
+0

Ich habe das schon viele Male zuvor auch versucht. Ich habe den Cookie-Header selbst gelesen und woanders gespeichert. – Nippysaurus

+0

Ich muss CookieContainer verwenden, da es die einzige Möglichkeit ist, Cookies an HttpWebRequest zu senden. – Salar

+0

Ich kann nicht glauben, dass ich endlich ein Szenario hatte, in dem das Framework von 4.0 auf 3.5 geändert wurde (ich benutzte keine 4.0 Sachen), brach mein Programm.Ich brauchte einige Zeit, um herauszufinden, warum die Session-Cookies für die Authentifizierung plötzlich fehlten. Sie haben dieses Problem in 4.0 behoben, also hat das Ändern des Frameworks einen Fehler in mein Programm eingeführt :-) – VVS

Antwort

24

Ich habe gerade das Update für diesen Fehler und hier diskutiert: http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html

Hier ist die Lösung:

  1. nicht verwenden .Add (Cookie), Nur Methode .Add (Uri, Cookie) verwenden.
  2. Rufen Sie BugFix_CookieDomain jedes Mal auf, wenn Sie dem Container ein Cookie hinzufügen, oder , bevor Sie .GetCookie verwenden oder bevor das System den Container verwendet.

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

Vielen Dank! Ich habe 2 Tage damit verbracht, das zu debuggen und dachte, dass ein Neuling wie ich lernen sollte, Bibliotheken selbst zu entwickeln. Aber es war ein Fehler! –

+0

Argh ... woher kommt _ContainerType? Mein Compiler wird es nicht finden! –

+0

Ah! Ich habe es gefunden ... Sie müssen _ContainerType durch cookieContainer.GetType() ersetzen –

0
//bug fix, exists only in 3.5 FW, please wrap it with defines 
//http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html 
if(!value.Contains("://www.")) //we are going to hit the bug 
{ 
    string urlWWW = value.Replace("://", "://www."); 
    Uri uriWWW = new Uri(urlWWW); 
    foreach (Cookie c in _cookieContainer.GetCookies(uriWWW)) 
     if (c.Domain.StartsWith(".")) 
      request.Headers["Cookies"] += c.Name + "=" + c.Value + ";"; //manually add the cookies 
} 
//~bug fix 
0

meinen Tag mit dieser Frage verloren. CallMeLaNN's Antwort hat mir nicht geholfen (ich benutze .Net 4.5). In meinem Fall war das Problem in der Reihenfolge der Einstellung von Anfrage- und Einstellungs-Cookies.

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

Ich habe für dieses Problem ein Update erstellt, das funktioniert:

  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(); 

Um es die erforderlich ist, ändern zu arbeiten:

In diesem Fall werden Cookies nicht an den Server gesendet werden unter Windows 10/UWP/.NET Core-Anwendungen. Das Problem ist, dass die Interna für CookieContainer unterschiedlich sind, aber genauso wie beschissen, wie sie im .NET Framework sind. Also die akzeptierte Lösung funktioniert nicht mehr.

Aber anstatt die CookieContainer "zu reparieren", schrieb ich gerade eine Version von GetCookies(), die alle Cookies für eine bestimmte Domäne mit einer Zeichenfolge erhält, unabhängig von ihrem "sicheren" Zustand oder wenn ihnen ein Punkt vorangestellt ist. Fühlen Sie sich frei, es zu modifizieren, wie Sie für Ihre Bedürfnisse sehen, und ich werde sehen, wie eine Version davon in einer zukünftigen .NET Core-Version implementiert wird.

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); 
     } 

    } 

}