2009-06-26 12 views
16

No estoy seguro de cómo CookieContainer maneja el dominio, así que creo esta prueba. Esta prueba muestra que cookieContainer no devuelve ninguna cookie para "example.com" pero de acuerdo con RFC debe devolver al menos 2 cookies.CookieContainer error?

¿No es un error?

¿Cómo hacer para que funcione?

Aquí está una discusión acerca de este error:

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

Lo he intentado muchas veces antes también. Terminé leyendo el encabezado de la cookie y almacenándola en otro lugar. – Nippysaurus

+0

Tengo que usar CookieContainer porque es la única forma de enviar cookies a HttpWebRequest. – Salar

+0

No puedo creer que finalmente tuve un escenario donde cambiar el marco de 4.0 a 3.5 (no estaba usando 4.0 cosas) rompió mi programa.Me llevó algo de tiempo averiguar por qué las cookies de sesión para la autenticación de repente no estaban. Solucionaron este problema en 4.0, por lo que cambiar el marco introdujo un error en mi programa :-) – VVS

Respuesta

24

solo he encontrado la solución para este error y se discuten aquí: http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html

Aquí está la solución:

  1. No utilice .Add (Cookie), use solo el método .Add (Uri, Cookie).
  2. Llame a BugFix_CookieDomain cada vez que agrega una cookie al contenedor o antes de usar .GetCookie o antes de que el sistema use el contenedor.

    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

¡Muchas gracias! Pasé 2 días depurando esto, pensando que un novato como yo debería aprender a buscar bibliotecas por mi cuenta. ¡Pero fue un error! –

+0

Argh ... ¿de dónde viene _ContainerType? ¡Mi compilador no lo encontrará! –

+0

¡Ah! Lo encontré ... Necesita reemplazar _ContainerType por cookieContainer.GetType() –

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

perdido mis días con este tema. La respuesta de CallMeLaNN no me ayudó (estoy usando .Net 4.5). En mi caso, el problema fue para configurar el cuerpo de las cookies de solicitud y configuración.

En este caso, las cookies no se enviarán al servidor:

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

para que funcione es necesario cambiar el orden:

  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

He creado una solución para este problema que funciona en aplicaciones Windows 10/UWP/.NET Core. El problema es que las partes internas para CookieContainer son diferentes, pero igual de mal gusto, ya que están en el .NET Framework propiamente dicho. Entonces la solución aceptada ya no funciona.

Pero en lugar de "arreglar" el CookieContainer, acabo de escribir una versión de GetCookies() que obtiene todas las cookies para un dominio en particular con una cadena, independientemente de su estado "seguro" o si están prefijados con un punto. Siéntase libre de modificarlo como mejor le parezca, y me ocuparé de que se implemente una versión en una versión futura de .NET Core.

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

    } 

} 
Cuestiones relacionadas