При разработке приложения типа клиент/сервер вам зачастую может понадобиться послать объект вашему клиенту. Наиболее легким путем для программиста при работе с объектом является получение всего объекта с сервера, а не только некоторых свойств. Одним из способов выполнения этого является использование WCF или Веб-сервисов, что предоставляет вам большой набор инструментов, таких как сериализация. Однако эти наборы технологий зачастую привносят немало перерасходов и сложностей в ваш проект, чего вам наверняка не хотелось бы видеть в случаях, когда вам необходимо просто переслать и получить один или более объектов.
При такой дилемме стоило потратить некоторое время на поиск решения. Нашей целью было нахождение простого и ясного метода создания объекта на сервере, его сериализация и отсылка обратно к клиенту. Безопасность и функциональная совместимость не входили в список задач, но они могут быть реализованы позже. Ограничением было то, что нам необходимо было быстрое решение, и оно должно было работать посредством стандартного HTTP-протокола.
Решение заключается в создании ASP.NET-страницы, которая считывает строку запроса для определения того, какой объект необходимо вернуть, создает его, сериализует его в двоичный формат и возвращает в виде двоичного приложения к клиенту. Клиент загружает файл при помощи класса WebClient() и преобразовывает его из последовательной формы в объект.
Как клиент, так и сервер используют библиотеку классов, содержащую общий объект. Поначалу мы реализовали это при помощи XML-сериализации, но она оказалась довольно медленной, но тем не менее вы можете ее использовать при необходимой функциональной совместимости.
Пояснения
Вам стоит помнить о том, что это не единственный способ - вы наверняка можете выполнить это при помощи WCF, используя специализированную привязку или MTOM, но нам кажется, что данные методы чересчур вовлечены и привносят ненужную сложность в простые проекты.
Использование кода
При загрузке страницы веб-сервера мы включаем следующий код для проверки того, какой объект требует клиент, и возвращаем объект, преобразованный в двоичное приложение.
protected void Page_Load(object sender, EventArgs e)
{
// Проверка того, какой объект необходим клиенту
if (Request.QueryString["op"] == "getdata")
{
// Создание нового экземпляра объекта с выборочными данными
var data = new SampleData();
data.moreData = 34343;
data.otherData = true;
data.SomeData = "fewoifjweofjwepo";
// Установка типа содержимого и заголовка
// байтовый поток позволяет нам посылать данные бинарного типа
// название файла здесь не относится к делу так как на самом деле
// он не используется клиентом
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition",
"attachment; filename=sampleData.bin");
// Сериализация объекта и запись его в ответный поток
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(Response.OutputStream, data);
// Важно завершить ответ, иначе клиенту будут посланы другие данные страницы
Response.End();
}
Со стороны клиента мы создали запрос к серверу используя строку запроса и преобразовали ответ.
// Создание ссылки для сервиса, она может быть сохранена в файле конфигурации
string url = "http://localhost/BinaryServiceSample/Default.aspx?op=getdata";
// Закрузка данных в битовый массив
// Эти данные содержат реальный объект
var client = new WebClient();
byte[] result = client.DownloadData(url);
// Создание потока данных для хранения объекта
var mem = new MemoryStream(result);
var binaryFormatter = new BinaryFormatter();
var data = (SampleData)binaryFormatter.Deserialize(mem);
mem.Close();
// Запись объекта в консоль
Console.Write(data.ToString());
Console.ReadLine();
Интересные факты
- Хотя двоичная сериализация может показаться более удобной, она может не быть совместимой с различными платформами.
- Сериализация объектов при помощи двоичной сериализации значительно быстрее, чем XML.
- Данный код не включает в себя проверку на ошибки, но это с легкостью можно внедрить. Мы не включили ее для простоты и удобства в изучении.
- Одним из способов добавить немного безопасности является шифрование битов и отсылка их клиенту. Это, конечно, сделает функциональную совместимость более сложной задачей.
- Дополнительная скорость в передаче данных может быть достигнута при помощи компрессии битов до их отсылки - ICSharpCode.SharpZipLib.dll может сжать биты памяти и при этом оно бесплатно, но вы также можете выполнить это при помощи .NET Framework путем реализации HTTP-компрессии и внедрения в ваш код.
- Сериализация объекта, на первый взгляд, придает больше контроля над тем, как все выполняется, причем не усложняя сам процесс.