У меня есть собственная служба WCF (платформа v4), которая предоставляется через пользовательскую привязку на основе HttpTransport
.Привязка использует пользовательский MessageEncoder
, который в значительной степени равен BinaryMessageEncoder
с добавлением функции сжатия gzip.
Silverlight и клиент Windows используют веб-службу.
Проблема : в некоторых случаях службе приходилось возвращать очень большие объекты и иногда выдавать исключения OutOfMemory при ответе на несколько одновременных запросов (даже если диспетчер задач сообщил о ~ 600 МБ для процесса).Исключение произошло в пользовательском кодировщике, когда сообщение собиралось сжать, но я считаю, что это был только симптом, а не причина.Исключение гласило: «не удалось выделить x Мб», где x было 16, 32 или 64, что не слишком много - по этой причине, я полагаю, что-то еще уже поставило процесс около некоторого предела до этого.
СлужбаКонечная точка определяется следующим образом:
var transport = new HttpTransportBindingElement(); // quotas omitted for simplicity
var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
Затем я провел эксперимент: я изменил TransferMode
с Buffered
на StreamedResponse
(и изменил клиента соответственно).Это новое определение сервиса:
var transport = new HttpTransportBindingElement()
{
TransferMode = TransferMode.StreamedResponse // <-- this is the only change
};
var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
Волшебно, больше никаких исключений OutOfMemory .Служба немного медленнее для небольших сообщений, но с ростом размера сообщения разница становится все меньше и меньше.Поведение (как для скорости, так и для исключений OutOfMemory) воспроизводимо, я провел несколько тестов с обеими конфигурациями, и эти результаты были согласованы.
Проблема решена, НО: я не могу объяснить, что здесь происходит.Мое удивление связано с тем, что я никак не менял договор .Т.е. я не создал контракт с одним параметром Stream
и т. Д., Как вы обычно делаете для потоковых сообщений.Я все еще использую свои сложные классы с тем же атрибутом DataContract и DataMember. Я только что изменил конечную точку , вот и все.
Я подумал, что установка TransferMode - это просто способ включить потоковую передачу для правильно сформированных контрактов, но, очевидно, есть больше, чемтот.Кто-нибудь может объяснить, что на самом деле происходит под капотом, когда вы меняете TransferMode
?