Подтвердить что ты не робот

Перенос больших полезных данных (Сериализованные объекты) с использованием wsHttp в WCF с защитой сообщений

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

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

Я должен добавить, что в моем случае меня действительно не беспокоит совместимость с другими клиентами по мере того, как мы владеем и контролируем каждую сторону связи и используем шаблон общего интерфейса для передачи данных с обеих сторон. Поэтому я открыт для любой идеи, которая вписывается в ограничения использования 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, поскольку эти методы требуют буферизации всех данных.
  • Канал каналов - Позволяет разбивать данные на отдельные сообщения, но на данный момент я не уверен в ограничениях, которые это имеет для дизайна контракта на обслуживание, и могу ли я использовать wsHttp с привязкой к сообщениям.

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

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

ok, основываясь на моем понимании, ситуация заключается в том, что клиент загружает некоторый большой объект сериализации через 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 shoud делает потоковое воспроизведение файлов автоматически и u dont ahve, чтобы беспокоиться о сериализованном размере объекта, поскольку мы используем передачу файлов. Не забывайте предельный отклик конфигурации.

Ответ 4

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

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

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

Ответ 5

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

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

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

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