С#: Написание CookieContainer на диск и загрузка обратно для использования
У меня есть CookieContainer
, извлеченный из сеанса HttpWebRequest/HttpWebResponse с именем CookieJar. Я хочу, чтобы мое приложение хранило файлы cookie между прогонами, поэтому файлы cookie, собранные в CookieContainer
в одном прогоне программы, также будут использоваться в следующем запуске.
Я думаю, что способ сделать это - это как-то написать содержимое CookieContainer на диск. Мой вопрос:
- Как вы можете написать CookieContainer на диск? Существуют ли встроенные функции для этого или, если нет, какие подходы люди предпринимают? Существуют ли какие-либо классы для упрощения этого?
- Как только вы написали CookieContainer на диск, , как вы его загрузите для использования?
ОБНОВЛЕНИЕ:. Первый ответ предложил сериализацию CookieContainer
. Однако я не очень хорошо разбираюсь в том, как сериализовать и десериализовать такие сложные объекты. Не могли бы вы предоставить код ? Было предложено использовать SOAPFormatter
.
Ответы
Ответ 1
Я не пробовал, но имеет атрибут Serializable и поэтому может быть [de] сериализован с .net-сериализацией .net, например. SoapFormatter.
Вот фрагмент кода, который вы просили.
var formatter = new SoapFormatter();
string file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "cookies.dat");
using (Stream s = File.Create (file))
formatter.Serialize(s, cookies);
...
CookieContainer retrievedCookies = null;
using (Stream s = File.OpenRead (file))
retrievedCookies = (CookieContainer) formatter.Deserialize(s);
Глядя на msdn, кажется, что SoapFormatter теперь устарел в .net 3.5, и он рекомендует использовать Binaryformatter. Раньше я нашел SoapFormatter полезным, поскольку файл доступен для чтения, что помогает при диагностике при неудачной десериализации! Эти форматы чувствительны к изменениям версии даже в версии сборки (поэтому, если вы десериализуетесь с одной версией фреймворка, обновите фреймворк, тогда он может не десериализоваться, не уверен), но есть способы обойти это с помощью свойства Binder, если это становится проблема. Я считаю, что они в первую очередь предназначены для краткосрочной стойкости/удаленности, но они могут быть достаточно хороши для вас здесь.
Новый DataContractSerializer, похоже, не работает с ним, так что он отсутствует.
Альтернативой было бы написать класс CookieContainerData для [de] сериализации с XmlSerializer и вручную преобразовать между этим и CookieContainer.
Ответ 2
Эта проблема искала меня целую вечность, я ничего не смог найти. Я проработал, поэтому отправляю эту информацию в мир.
Ответ с использованием BinaryFormatter:
public static void WriteCookiesToDisk(string file, CookieContainer cookieJar)
{
using(Stream stream = File.Create(file))
{
try {
Console.Out.Write("Writing cookies to disk... ");
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, cookieJar);
Console.Out.WriteLine("Done.");
} catch(Exception e) {
Console.Out.WriteLine("Problem writing cookies to disk: " + e.GetType());
}
}
}
public static CookieContainer ReadCookiesFromDisk(string file)
{
try {
using(Stream stream = File.Open(file, FileMode.Open))
{
Console.Out.Write("Reading cookies from disk... ");
BinaryFormatter formatter = new BinaryFormatter();
Console.Out.WriteLine("Done.");
return (CookieContainer)formatter.Deserialize(stream);
}
} catch(Exception e) {
Console.Out.WriteLine("Problem reading cookies from disk: " + e.GetType());
return new CookieContainer();
}
}
Ответ 3
Другой альтернативой является использование сериализации Json (Json.NET):
// other includes
using Newtonsoft.Json;
Класс с файлом cookie:
public class WithCookie
{
public Cookie MyCookie { get; set; }
public WithCookie()
{
MyCookie = new Cookie("CF788DF", "A cookie value!", "/", ".test.com");
}
}
Вот как сериализовать его в Json:
class Program
{
static void Main(string[] args)
{
try
{
WithCookie wc1 = new WithCookie();
// Expires a month from now
wc1.MyCookie.Expires = DateTime.Now.AddMonths(1);
string wc1json = JsonConvert.SerializeObject(new WithCookie());
WithCookie wc2 = JsonConvert.DeserializeObject < WithCookie>(wc1json);
string wc2json = JsonConvert.SerializeObject(wc2);
if (wc2json == wc1json)
{
Console.WriteLine("HORRAY!");
}
else
{
// The strings will not be equal, because the Cookie.TimeStamp
// changes but the cookies are in fact the same!
Console.WriteLine("FAIL!");
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.ToString());
}
Console.ReadKey();
}
}