学无先后达者为师!
不忘初心,砥砺前行。

摒弃反射:.NET 6 为序列化 CookieContainer 提供了新方法

CookieContainer 对象可以用于在 HTTP 请求间传递 Cookie 信息。如果我们需要向 CookieContainer 中添加一条数据,可以采用其 Add 方法:

var cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name", "Soar360", "/", "httpbin.org"));
using (var handler = new HttpClientHandler
{
	UseCookies = true,
	CookieContainer = cookieContainer
})
{
	using (var http = new HttpClient(handler))
	{
		var json = await http.GetStringAsync("https://httpbin.org/cookies");
		Console.WriteLine(json);
	}
}

以上代码的输出如下:

{
  "cookies": {
    "name": "Soar360"
  }
}

有时我们需要将 CookieContainer 进行持久化(序列化),将其保存到本地文件或数据库中(比如当 Cookie 包含了对某个资源的访问凭据时)。很长一段时间中,我们只能通过反射来实现该功能:

public static CookieCollection GetAllCookies(CookieContainer cookieJar)
{
    CookieCollection cookieCollection = new CookieCollection();

    Hashtable table = (Hashtable) cookieJar.GetType().InvokeMember("m_domainTable",
                                                                    BindingFlags.NonPublic |
                                                                    BindingFlags.GetField |
                                                                    BindingFlags.Instance,
                                                                    null,
                                                                    cookieJar,
                                                                    new object[] {});

    foreach (var tableKey in table.Keys)
    {
        String str_tableKey = (string) tableKey;

        if (str_tableKey[0] == '.')
        {
            str_tableKey = str_tableKey.Substring(1);
        }

        SortedList list = (SortedList) table[tableKey].GetType().InvokeMember("m_list",
                                                                    BindingFlags.NonPublic |
                                                                    BindingFlags.GetField |
                                                                    BindingFlags.Instance,
                                                                    null,
                                                                    table[tableKey],
                                                                    new object[] { });

        foreach (var listKey in list.Keys)
        {
            String url = "https://" + str_tableKey + (string) listKey;
            cookieCollection.Add(cookieJar.GetCookies(new Uri(url)));
        }
    }

    return cookieCollection;
}

测试代码:

CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name1", "value1", "/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name1", "value1", "/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".sum16.com"));

CookieCollection cookies = GetAllCookies(cookieContainer);

Console.WriteLine(JsonConvert.SerializeObject(cookies, Newtonsoft.Json.Formatting.Indented));	

输出:

[
  {
    "Comment": "",
    "CommentUri": null,
    "HttpOnly": false,
    "Discard": false,
    "Domain": ".coderbusy.com",
    "Expired": false,
    "Expires": "0001-01-01T00:00:00",
    "Name": "name2",
    "Path": "/path1/path2/",
    "Port": "",
    "Secure": false,
    "TimeStamp": "2021-11-13T11:31:20.3900972+08:00",
    "Value": "value1",
    "Version": 0
  },...
]

幸运的是,随着 .NET 6 的正式发布,CookieContainer 类型新增了一个名为 GetAllCookies() 的实例方法,该方法可以获取到 CookieContainer 中所有的 Cookie 信息,并填充 CookieCollection 。所以测试代码可以改为:

CookieContainer cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("name1", "value1", "/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".coderbusy.com"));
cookieContainer.Add(new Cookie("name1", "value1", "/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/", ".sum16.com"));
cookieContainer.Add(new Cookie("name2", "value1", "/path1/path2/", ".sum16.com"));

CookieCollection cookies = cookieContainer.GetAllCookies();

Console.WriteLine(JsonConvert.SerializeObject(cookies, Newtonsoft.Json.Formatting.Indented));	

该代码会产生同样的输出,但明显更加直观和优雅。

赞(1) 打赏
未经允许不得转载:码农很忙 » 摒弃反射:.NET 6 为序列化 CookieContainer 提供了新方法

评论 抢沙发

给作者买杯咖啡

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册