笔者之前的文章:摒弃反射:.NET 6 为序列化 CookieContainer 提供了新方法 中所使用的代码对 CookieCollection 对象进行了 JSON 序列化。在该文章发布后笔者对该项目所用的技术投入了实战,然而并不成功。
假设有以下代码:
var cookie = new CookieContainer(); cookie.Add(new Cookie("c1", "v1", "/", "httpbin.org")); cookie.Add(new Cookie("c2", "v2", "/", "httpbin.org")); cookie.Add(new Cookie("c3", "v3", "/", "httpbin.org")); cookie.Add(new Cookie("c4", "v4", "/", "httpbin.org")); var http = new HttpClient(new HttpClientHandler { UseCookies = true, CookieContainer = cookie }); var ret = await http.GetStringAsync("https://httpbin.org/cookies"); Console.WriteLine(ret);
这会产生正常的输出:
{ "cookies": { "c1": "v1", "c2": "v2", "c3": "v3", "c4": "v4" } }
下面的代码会将一个 CookieCollection 序列化为 JSON 字符串:
static string GetJson() { var cookie = new CookieContainer(); cookie.Add(new Cookie("c1", "v1", "/", "httpbin.org")); cookie.Add(new Cookie("c2", "v2", "/", "httpbin.org")); cookie.Add(new Cookie("c3", "v3", "/", "httpbin.org")); cookie.Add(new Cookie("c4", "v4", "/", "httpbin.org")); var collection = cookie.GetAllCookies(); var json = JsonConvert.SerializeObject(collection); return json; }
使用反序列化并构造请求:
var cookie = new CookieContainer(); var collection = JsonConvert.DeserializeObject<CookieCollection>(GetJson()); collection.Add(new Cookie("c5", "v5", "/", "httpbin.org")); cookie.Add(collection); var http = new HttpClient(new HttpClientHandler { UseCookies = true, CookieContainer = cookie }); var ret = await http.GetStringAsync("https://httpbin.org/cookies"); Console.WriteLine(ret);
发现只有后面手动添加的 c5 被正确输出了:
{ "cookies": { "c5": "v5" } }
该问题的发生原因笔者并未深究,从 LINQPad 的 Dump 输出上看应该不是公共属性差异造成的:
一个简单的解决方案是引入一个自定义的 CookieInfo 对象:
public class CookieInfo { public CookieInfo() { } public CookieInfo(Cookie cookie) { this.Name = cookie.Name; this.Value = cookie.Value; this.Path = cookie.Path; this.Domain = cookie.Domain; } public string Name { get; set; } public string Value { get; set; } public string Path { get; set; } public string Domain { get; set; } public Cookie ToCookie() { return new Cookie(this.Name, this.Value, this.Path, this.Domain); } }
在序列化和反序列化时,使用 CookieInfo 替代即可:
static string GetJson() { var cookie = new CookieContainer(); cookie.Add(new Cookie("c1", "v1", "/", "httpbin.org")); cookie.Add(new Cookie("c2", "v2", "/", "httpbin.org")); cookie.Add(new Cookie("c3", "v3", "/", "httpbin.org")); cookie.Add(new Cookie("c4", "v4", "/", "httpbin.org")); var collection = cookie.GetAllCookies(); var json = JsonConvert.SerializeObject(collection.Select(i => new CookieInfo(i))); return json; } async Task Main() { var cookie = new CookieContainer(); var list = JsonConvert.DeserializeObject<List<CookieInfo>>(GetJson()); var collection = new CookieCollection(); foreach (var item in list) { collection.Add(item.ToCookie()); } collection.Add(new Cookie("c5", "v5", "/", "httpbin.org")); cookie.Add(collection); var http = new HttpClient(new HttpClientHandler { UseCookies = true, CookieContainer = cookie }); var str = await http.GetStringAsync("https://httpbin.org/cookies"); Console.WriteLine(str); }
总结
本文算是对之前文章的一个补丁。事实上,笔者每次落笔都会深思熟虑:既担心自己表达不善,也忧虑散播了错误的知识误导别人。