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

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

总结

本文算是对之前文章的一个补丁。事实上,笔者每次落笔都会深思熟虑:既担心自己表达不善,也忧虑散播了错误的知识误导别人。

赞(0) 打赏
未经允许不得转载:码农很忙 » 在 .NET 开发中请不要序列化 CookieCollection 和 Cookie 对象

评论 抢沙发

给作者买杯咖啡

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

支付宝扫一扫

微信扫一扫

登录

找回密码

注册