在 .NET 开发中请不要序列化 CookieCollection 和 Cookie 对象
笔者之前的文章:摒弃反射:.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);
}
欢迎来到:码农很忙 。