WCF возвращает пользовательский объект с коллекцией пользовательских объектов, содержащих потоки - PullRequest
0 голосов
/ 09 октября 2009

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

когда я пытаюсь вернуть этот объект, я получаю

System.Runtime.Serialization.InvalidDataContractException: Тип 'System.ServiceModel.Dispatcher.StreamFormatter + MessageBodyStream' не может быть сериализован. Попробуйте пометить его атрибутом DataContractAttribute и пометить все его элементы, которые вы хотите сериализовать, атрибутом DataMemberAttribute. См. Документацию Microsoft .NET Framework для других поддерживаемых типов.

Если я перехожу на метод, чтобы просто вернуть один поток с потоком в качестве возвращаемого типа, он работает нормально. Это было бы слишком много кода для публикации, поэтому мне просто интересно, если это возможно, и если есть что-то особенное, что я должен сделать, чтобы пользовательский объект с потоками возвращался без ошибок из службы WCF?

Я сейчас использую wsHttpBindig во время тестирования.

Я пометил потоки и IList как DataMembers в классах, я должен пометить их как-нибудь еще?

Спасибо за любую помощь, если это не понятно, я могу попытаться создать небольшой пример кода

Ответы [ 3 ]

4 голосов
/ 09 октября 2009

Вы действительно хотите, чтобы потоковая передача происходила или вы просто хотите, чтобы она сериализовалась (и все в порядке с буферизацией)?

Если вы согласны с буферизацией:

Имейте в виду, что DataContractSerializer не имеет встроенной поддержки потоков, но он поддерживает байтовые массивы. Итак, сделайте обычный трюк преобразования типов DataContract: не помечайте поток с помощью DataMember, но создайте частное свойство [DataMember] типа byte [], которое обертывает поток. Что-то вроде:

public Stream myStream;

[DataMember(Name="myStream")]
private byte[] myStreamWrapper {
   get { /* convert myStream to byte[] here */ }
   set { /* convert byte[] to myStream here */ }
}

Если вы действительно хотите, чтобы он транслировался:

WCM ServiceModel может поддерживать потоковое тело сообщения только в том случае, если поток является всем телом. Итак, ваша операция должна возвращать MessageContract, который возвращает все вещи, не относящиеся к Stream, в качестве заголовков. Вот так:

[MessageContract]
public class MyMessage {
   [MessageHeader]
   public MyDataContract someInfo;
   [MessageBody]
   public Stream myStream;
}
2 голосов
/ 09 октября 2009

Короче говоря: вы не можете смешивать буферизованную передачу (отправляя обратно int, string или пользовательские сложные типы, помеченные как DataContracts) с потоковой передачей.

Хорошо задокументировано здесь: MSDN для потоковой передачи WCF .

Там написано:

Ограничения на потоковые передачи

Использование режима потоковой передачи заставляет время выполнения применять дополнительные ограничения.

Операции, которые происходят через Потоковый транспорт может иметь контракт с не более одного входа или выхода Параметр . Этот параметр соответствует на весь текст сообщения и должно быть Сообщение, производный тип Stream или IXmlSerializable реализация. Имея возвращаемое значение для операции эквивалентно с выходным параметром.

Так что, я думаю, вам придется перестроить свое решение, чтобы оно имело два метода: один, который возвращает основную информацию в сложном типе, и вторую операцию, которая обрабатывает потоковую передачу.

Марк

0 голосов
/ 09 октября 2009

Это кажется дублирующим вопросом - см. Мой ответ на WCF, возвращающий пользовательский объект с коллекцией пользовательских объектов, содержащих потоки для решения.

Кстати

Когда вы используете Stream непосредственно в [OperationContract], это особый случай. DataContractSerializer даже не вызывается. WCM ServiceModel использует специальный способ для записи тела сообщения с использованием потока (гарантируя, что оно действительно передается в потоковом режиме, если базовая привязка его поддерживает).

Но когда вы используете Stream как просто еще один [DataMember] внутри [DataContract], это просто еще один тип для DataContractSerializer, и при этом он не поддерживается. Поэтому вы должны использовать трюк преобразования типов (см. Мою предыдущую ссылку).

Не интуитивно, я знаю :) Но задокументировано до некоторой степени здесь и здесь .

...