У меня есть случай, когда мне нужно передать большие объемы сериализованных графов объектов (через NetDataContractSerializer) с использованием WCF с помощью wsHttp. Я использую безопасность сообщений и хотел бы продолжать это делать. Используя эту настройку, я хотел бы передать сериализованный граф объектов, который может иногда приближаться к 300 МБ или около того, но когда я пытаюсь это сделать, я начал видеть исключение типа System.InsufficientMemoryException.
После небольшого исследования выяснилось, что по умолчанию в WCF результат для вызова службы содержится в одном сообщении по умолчанию, которое содержит сериализованные данные, и эти данные буферизуются по умолчанию на сервере, пока все сообщение не будет полностью написано. Таким образом, исключение памяти вызвано тем, что на сервере заканчиваются ресурсы памяти, которые ему разрешено выделять, потому что этот буфер заполнен. Две основные рекомендации, с которыми я столкнулся, - это использовать потоки или фрагменты для решения этой проблемы, однако мне не ясно, что это значит, и возможно ли решение с моей текущей настройкой (wsHttp/NetDataContractSerializer/Message Security). До сих пор я понимаю, что использование безопасности потокового сообщения не будет работать, потому что шифрование и дешифрование сообщений должны работать на весь набор данных, а не на частичное сообщение. Похоже, что Chunking звучит так, как будто это возможно, но мне непонятно, как это было бы сделано с другими ограничениями, которые я перечислил. Если бы кто-нибудь мог предложить некоторые рекомендации о том, какие решения доступны и как их реализовать, я бы очень признателен.
Я должен добавить, что в моем случае меня действительно не беспокоит совместимость с другими клиентами по мере того, как мы владеем и контролируем каждую сторону связи и используем шаблон общего интерфейса для передачи данных с обеих сторон. Поэтому я открыт для любой идеи, которая вписывается в ограничения использования wsHttp с защитой сообщений для переноса графиков объектов, сериализованных с использованием NetDataContractSerializer, и я предпочитаю решение, в котором я не должен резко менять существующие службы и окружающую инфраструктуру.
Связанные ресурсы:
- Канал каналов
- Инструкции по включению потоковой передачи
- Большие вложения по WCF
- Пользовательский кодер сообщений
- Еще одно определение НедостаточноMemoryException
- Необходим канал передачи недуплексного канала
- Потоковая передача большого содержимого с помощью WCF и отложенного исполнения
Я также заинтересован в любом типе сжатия, которое можно было бы сделать с этими данными, но похоже, что мне, вероятно, было бы лучше сделать это на транспортном уровне, как только я смогу перейти на .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. Если кто-то может просто ответить на эти вопросы для меня, я награжу их щедростью и отметьте это как ответ.