문제

CookieContainer가 도메인을 처리하는 방법이 혼란 스러워서이 테스트를 만듭니다. 이 테스트는 CookieContainer가 "example.com"에 대한 쿠키를 반환하지 않지만 RFC에 따르면 최소 2 개의 쿠키를 반환해야합니다.

버그가 아닌가요?

어떻게 작동합니까?

이 버그에 대한 토론은 다음과 같습니다.

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>
도움이 되었습니까?

해결책

방금이 버그에 대한 수정 사항을 찾아서 여기에서 논의했습니다.http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain handling-bug-fix.html

다음은 해결책입니다.

  1. .add (쿠키)를 사용하지 말고 .add (uri, 쿠키) 메소드 만 사용하십시오.
  2. 컨테이너에 쿠키를 추가 할 때마다 또는 .getCookie를 사용하기 전에 또는 시스템이 컨테이너를 사용하기 전에 Bugfix_Cookiedomain으로 전화하십시오.

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

다른 팁

//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

이 문제로 하루를 잃었습니다. Callmelann의 응답은 도움이되지 않았습니다 (.NET 4.5를 사용하고 있습니다). 제 경우에는 문제가 요청 본문을 설정하고 쿠키를 설정하는 것이 었습니다.

이 경우 쿠키는 서버로 전송되지 않습니다.

            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 Core 앱에서 작동하는이 문제에 대한 수정을 만들었습니다. 문제는 내부를위한 것입니다 CookieContainer .NET 프레임 워크에 적합한 것처럼 다르지만 엉뚱한 것입니다. 따라서 허용 된 솔루션은 더 이상 작동하지 않습니다.

그러나 "고정"하는 대신 CookieContainer, 방금 버전을 썼습니다 GetCookies() "보안"상태에 관계없이 또는 점으로 접두사가있는 경우에 관계없이 특정 도메인에 대한 모든 쿠키를 사용합니다. 귀하의 요구에 적합한대로 자유롭게 수정하십시오. 향후 .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);
        }

    }

}

다음은이 버그를 해결하기위한 해킹입니다.http://social.microsoft.com/forums/en-us/netfxnetcom/thread/1297afc1-12d4-4d75-8d3f-756322d234c반사를 사용합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top