Проблема WCF с передачей сложных типов
Вопрос
У меня есть контракт службы, который определяет метод с параметром типа System.Object (xs:anyType в WSDL).Я хочу иметь возможность передавать в этом параметре как простые, так и сложные типы.Простые типы работают нормально, но когда я пытаюсь передать сложный тип, определенный в моем WSDL, я получаю следующую ошибку:
Элемент 'http://tempuri.org/:значение'содержит данные 'http://schemas.datacontract.org/2004/07/MyNamespace:MyClass'контракт данных.Десериализатор не знает ни одного типа, который соответствует этому контракту.Добавьте тип, соответствующий «MyClass», в список известных типов, например, используя атрибут KnownTypeAttribute или добавив его в список известных типов, переданных в DataContractSerializer.
Добавление его как известного типа не помогает, поскольку он уже есть в моем WSDL.Как передать объект сложного типа через параметр «xs:anyType»?
Больше информации:
Я считаю, что это работает при использовании NetDataContract, но я не могу это использовать, поскольку мой клиент — Silverlight.
Я видел ссылки на сложные типы, явно расширяющие xs:anyType, но понятия не имею, как заставить WCF генерировать WSDL, который делает это, и понятия не имею, поможет ли это вообще.
Спасибо
Решение 3
Я решил эту проблему, используя атрибут ServiceKnownType.Я просто добавляю свой сложный тип в качестве известного типа службы в свой контракт службы, и ошибка исчезает.Я не уверен, почему это не сработало, когда я пробовал это в прошлый раз.
Похоже, это никак не влияет на WSDL, поэтому я подозреваю, что сериализованный поток должен иметь некоторую разницу, сообщающую десериализатору, что объект может быть десериализован с использованием моего типа.
Другие советы
NetDataContract работает, поскольку NetDataContractSerializer включает информацию о типе.
Атрибут KnownType указывает DataContractSerializer, как десериализовать сообщение.Поскольку эта информация зависит от реализации, это дополнительная информация, определенная в публичном контракте и не принадлежащая WSDL.
Вы никогда не сможете передать какой-либо старый тип данных, поскольку десериализатору необходимо определить соответствующий тип и создать экземпляр.
Возможно, вы сможете получить известные типы во время выполнения, а не жестко запрограммировать их в DataContract.Взглянем здесь для образца.
Я надеюсь, что это поможет.Я видел, как мой коллега использовал этот код для отправки сложных типов данных, и для меня это довольно просто.Это использовалось с BasicHttpBinding и очень хорошо работает с MOSS BDC, а также с другими приложениями, использующими базовую привязку.
- Создайте контракт данных на основе универсального класса.
Используйте контракт данных, когда информацию необходимо отправить.
[DataContract(Пространство имен = "http://Service.DataContracts", Name =" ServiceAtacontractBase ")] открытый класс ServiceAtacontract {
public ServiceDataContract() { } public ServiceDataContract(TValueType Value) { this.m_objValue = Value; } private TValueType m_objValue; [DataMember(IsRequired = true, Name = "Value", Order = 1)] public TValueType Value { get { return m_objValue; } set { m_objValue = value; } }
}
Используйте этот контракт данных везде, где это необходимо, в функциях WCF, возвращающих сложный тип данных.Например:
public ServiceDataContract<string[]> GetStrings()
{
string[] temp = new string[10];
return new ServiceDataContract<string[]>(temp);
}
Обновлять:ServiceDataContract — это универсальный класс, использующий TValueType.Он не отображается из-за проблем с рендерингом HTML.
Попробуйте использовать суррогаты контракта данных для сопоставления неподдерживаемых объектов, специфичных для точечной сети или несовместимых типов.Видеть MSDN
На данный момент я решил эту проблему, создав новый тип контракта данных, который может обертывать либо другой тип контракта данных, либо простой тип.Вместо передачи типа Object теперь я передаю этот класс-оболочку.Это работает нормально, но мне все равно хотелось бы знать, есть ли решение исходной проблемы.
Я попытался добавить атрибут ServiceKnownType, указав тип, который пытаюсь передать, но все равно получаю ту же ошибку. Я также попытался добавить атрибут KnownType в свой контракт данных (что казалось глупым, поскольку он был того же типа, что и контракт данных).Я предполагаю, что добавление их во время выполнения не поможет, если добавление их во время компиляции не поможет.
Если бы я расширял другой сложный тип, мне кажется, что я бы хотел добавить атрибут KnownType к этому базовому типу.Но поскольку мой базовый тип — Object, я не вижу способа сделать это.
Что касается суррогатов, мне кажется, что они используются для типов-оберток, для которых не определен контракт.Однако в моем случае контракт определен.