Передача больших полезных данных (сериализованных объектов) с использованием wsHttp в WCF с защитой сообщений - PullRequest
16 голосов
/ 10 июня 2010

У меня есть случай, когда мне нужно передать большое количество сериализованных графов объектов (через NetDataContractSerializer ), используя WCF, используя wsHttp.Я использую безопасность сообщений и хотел бы продолжать это делать.Используя эту настройку, я хотел бы перенести сериализованный граф объектов, который иногда может приближаться к 300 МБ или около того, но когда я пытаюсь это сделать, я начинаю видеть исключение типа System.InsufficientMemoryException.

После небольшого исследования выясняется, что по умолчанию в WCF результат вызова службы содержится в одном сообщении по умолчанию, которое содержит сериализованные данные, и эти данные по умолчанию буферизуются на сервере до полногосообщение полностью написано.Таким образом, исключение памяти вызвано тем фактом, что серверу не хватает ресурсов памяти, которые ему разрешено выделять, поскольку этот буфер заполнен.Две основные рекомендации, с которыми я столкнулся, - это использование потоковой передачи или разбиения на фрагменты для решения этой проблемы, однако мне не ясно, что это включает и возможно ли какое-либо решение с моей текущей настройкой (wsHttp / NetDataContractSerializer / Message Security).До сих пор я понимаю, что использование безопасности потоковых сообщений не сработает, поскольку шифрование и дешифрование сообщений должны работать со всем набором данных, а не с частичным сообщением.Чанкинг, однако, звучит так, как будто это возможно, однако мне не ясно, как это будет сделано с другими ограничениями, которые я перечислил.Если бы кто-нибудь мог предложить какое-то руководство относительно того, какие решения доступны и как его реализовать, я был бы очень признателен.

Я должен добавить, что в моем случае я действительно не беспокоюсь о совместимости с другими клиентами, так как мывладеть и контролировать каждую сторону связи и использовать шаблон общего интерфейса для данных, передаваемых любой стороне.Так что я открыт для любой идеи, которая вписывается в ограничения использования wsHttp с защитой сообщений для передачи графов объектов, сериализованных с использованием NetDataContractSerializer, и я предпочитаю решение, при котором мне не нужно резко менять существующие сервисы и окружающую инфраструктуру.

Связанные ресурсы:

Меня также интересует любой тип сжатия, который можно выполнить наэти данные, но, похоже, мне лучше всего сделать это на транспортном уровне, как только я смогу перейти на .NET 4.0, чтобы клиент автоматически поддерживал заголовки gzipесли я правильно понимаю.

Обновление (2010-06-29):

Немного истории о том, как я пришел к выводу, что слишком большое буферизованное сообщение вызывало мою проблему.Первоначально я видел CommunicationException ниже во время тестирования.

Базовое соединение было закрыто: соединение было неожиданно закрыто.

В конце концов после запуска этого ивыполняя еще несколько журналов, я обнаружил базовое исключение InsufficientMemoryException , которое вызывало проблему с указанным сообщением.

Не удалось выделить буфер управляемой памяти в 268435456 байт.Объем доступной памяти может быть низким.

, который возник из следующего метода.

System.ServiceModel.Diagnostics.Utility.AllocateByteArray (размер Int32)

Другими словами, сбой произошел из-за выделения массива. При записи одних и тех же данных, сериализованных на диск, это занимает около 146 МБ, и если я урежу их вдвое, я перестану получать сообщение об ошибке, однако я больше не копался в конкретном пороговом значении, которое нарушает мой буфер, и в зависимости от того, относится ли оно к моей системе или нет.

Обновление (2010-12-06):

Полагаю, на данный момент я ищу уточнения для следующего. Насколько я понимаю, по умолчанию с WCF wsHttp с защитой сообщений, что целое сообщение (как правило, весь набор данных, которые я возвращаю) необходимо буферизовать на сервере, прежде чем ответ будет отправлен обратно клиенту, что вызовет мои проблемы.

Возможные решения:

  • Ограничение размера данных - с помощью некоторой формы сжатия, кодирования или ограничения фактических данных, возвращаемых с использованием какого-либо метода, подобного поисковому вызову, чтобы избежать использования максимальной емкости исходящего буфера.
  • Потоковая передача - позволяет передавать большие объемы данных через WCF потоковым способом, однако это несовместимо с wsHttp или MessageSecurity, поскольку эти методы требуют буферизации всех данных.
  • Chunking Channel - позволяет разбивать данные на отдельные сообщения, но на данный момент я не уверен в ограничениях, которые это имеет для дизайна контракта на обслуживание, и могу ли я все еще использовать wsHttp с привязкой сообщений.

Ограничение данных, которые я могу вернуть, работает только до определенного момента, и, как и при использовании параметра «Потоковая передача», эти параметры требуют кодирования большей части работы более низкого уровня вне вызовов службы WCF. Поэтому я думаю, что мне нужно знать, может ли любая возможная реализация канала чанкинга обойти большие проблемы с сообщениями, позволяя разбивать один набор данных на отдельные сообщения на сервере и затем объединять их на клиенте в таким образом, что мне не нужно менять интерфейс / форму существующих сервисных контрактов и таким образом, что процесс в значительной степени скрыт от клиентской и серверной частей каждой реализации сервиса, все еще используя защиту сообщений и wsHttp. Если канал chunking потребует, чтобы я переписал свои сервисные контракты, чтобы показать потоки, то я не вижу, как это на самом деле отличается от потокового решения. Если кто-то может просто ответить на эти вопросы для меня, я награжу их премией и отмечу ее как ответ.

Ответы [ 5 ]

3 голосов
/ 04 декабря 2010

protobuf-net обычно имеет значительную экономию пространства (например, в порядке порядка) для большинства данных и может подключаться к WCF.К сожалению на данный момент не поддерживает полные графики, только деревья.Тем не менее, у меня есть планы , которые я просто не успел осуществить.Я ничего не могу обещать, но я мог бы попытаться поднять эту работу немного раньше.

В противном случае;могут быть способы настроить существующий код для работы с деревом вместо графа.

2 голосов
/ 07 декабря 2010

Я использовал для передачи своего большого текста в / из wcf. Мой триг - преобразовать его в поток и использовать GZipStream для сжатия, а затем отправить его как byte [], к счастью, его никогда не будет превышать 10 МБ.

В вашем случае я рекомендую сделать фрагментацию. Преобразовать сериализованный объект в byte [], затем объединить и распаковать

psudo

int transferSize = 5000000; // 5MB
byte[] compressed = ...;
var mem = new System.IO.MemoryStream(compressed);

for(int i = 0; i < compressed .length; i+= transferSize )
{
    byte[] buffer = new byte[transferSize];
    mem.Read(buffer, i, compressed);
    mem.Flush();
    sendFragmentToWCF(buffer);
}

редактировать 08 декабря 2010

хорошо, насколько я понимаю, ситуация такова, что клиент загружает какой-то большой объект сериализации через WCF. Я не особо тестировал это решение, но думаю, оно должно работать. Ключ - сохранить сериализованный объект в файл и использовать Response для передачи этого файла.

[WebMethod]
public void GetSerializedObject()
{
    string path = @"X:\temp.tmp";

    var serializer = new  System.Runtime.Serialization.NetDataContractSerializer();
    var file = new System.IO.FileStream(path, System.IO.FileMode.CreateNew);

    try
    {
        serializer.Serialize(file, ...);
        this.Context.Response.TransmitFile(path);
        this.Context.Response.Flush();
    }
    finally
    {
        file.Flush();
        file.Close();
        file.Dispose();
        System.IO.File.Delete(path);
    }
}

WCF должен автоматически выполнять потоковую передачу файлов, и вам не нужно беспокоиться о размере сериализованного объекта, поскольку мы используем передачу файлов. Не забудьте указать предел ответа конфигурации.

2 голосов
/ 30 июня 2010

Если вы все еще хотите использовать Message Security, я бы порекомендовал вам использовать MTOM для оптимизации пропускной способности сети, которая должна использоваться для передачи сообщений, а также канала чанкинга для использования меньших буферов памяти при применении безопасности.В противном случае WCF попытается загрузить все сообщение в память для обеспечения безопасности, и поэтому вы получите исключение Недостаточно памяти.

0 голосов
/ 12 декабря 2011

Поскольку никто не выпустил его, возможно, с помощью методов WebSockets или long polling можно решить эту проблему.Я только кратко рассмотрел эти решения и не разработал решение вокруг них, но я хотел предложить эти концепции для записи, и я расширю свой ответ позже, если позволит время.

Основная идея заключается в достижении чего-то похожего на идею работы примера ChunkingChannel, но при этом не требуется полнодуплексный канал, который обычно нарушает модель запросов / ответов на основе веб-порта 80, что нежелательно для создания брандмауэра и других устройств.связанные конфигурации для клиентов.

Другие связанные материалы:

Обновление: после более подробного изучения этого вопроса выясняется, что при использовании WebSockets, который известен как NetHttpBinding, по своей сути я не буду решать исходный запрос, который заключается в использовании wsHttp в WCF с безопасностью сообщений.Однако я собираюсь оставить здесь свой ответ в качестве информации для тех, кто может искать альтернативу.

0 голосов
/ 06 декабря 2011

Некоторым более легким, но не гарантированным решением было бы

  • использовать вместо DataContractSerializer, поскольку у вас есть обе стороны.Для этого не требуется информация о встроенном типе, которая значительно больше.
  • используйте [DataMember(EmitDefaultValue = false)], который обсуждается в вопросе, который я задал - опять же, потому что у вас есть обе стороны;это уменьшит размер сообщения (конечно, насколько это зависит от количества полей в графике по умолчанию).
  • используйте [DataContract(IsReference=true)], особенно если у вас много повторяющихся объектов значений или справочных данных
  • использует какое-то регулирование на сервере, чтобы уменьшить нагрузку на память одновременных результатов

Это, конечно, компромиссы, например, с удобочитаемостью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...