Я пытался использовать клиент Silverlight для вызова сервиса WCF ASP.NET, который возвратил бы a Dictionary
. Это хорошо работало, когда значения в словаре были простыми типами как int
, string
или Guid
.
Однако у меня теперь есть сценарий, где мне нужно одно из значений, чтобы быть массивом Dictionary
! Все это компилирует прекрасный, и подпись сервиса не изменилась, но служебный вызов теперь перестал работать.
Какие-либо идеи, как зафиксировать его? У меня есть попытка аннотировать мой класс обслуживания и методы с KnownType
и ServiceKnownType
атрибуты, но это не работало.
Вот часть кода:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
[OperationContract]
[ServiceKnownType(typeof(Dictionary))]
public Dictionary GetObject()
{
return new Dictionary()
{
{ "pty1", 1 },
{ "pty2", Guid.NewGuid() },
{ "pty3", "blah" },
{ "pty4", new Dictionary[]
{
new Dictionary()
{
{ "pty1", 4 },
{ "pty2", Guid.NewGuid() },
{ "pty3", "blah" },
}
,
new Dictionary()
{
{ "pty1", 4 },
{ "pty2", Guid.NewGuid() },
{ "pty3", "blahblah" },
}
}
}
};
}
}
Спасибо за Ваши ответы. Я включил трассировку WCF и, как подозревается, во время сериализации существует проблема. Проблемой не является сериализация Dictionary
но тот Array
из Dictionary
.
Здесь исключение, зарегистрированное сервисом WCF.
Была ошибка при попытке сериализировать параметр: GetObjectResult. Сообщение InnerException было 'Типом 'Система. Наборы. Универсальный. Словарь' 2 [[Система. Строка, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], [Система. Объект, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] []' с названием контракта данных 'ArrayOfArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' не ожидаются. Добавьте, что любые типы, не известные статически списку известных типов - например, при помощи атрибута KnownTypeAttribute или путем добавления их к списку известных типов, передали DataContractSerializer'.. Дополнительную информацию см. в InnerException.
У меня есть также попытка определить новое DataContract
класс с единственным элементом данных, но это приводит к той же самой ошибке.
Вот код для который, сопровождается исключением, зарегистрированным входом WCF.
[DataContract]
[KnownType(typeof(ObjectHolder))]
public class ObjectHolder
{
[DataMember]
public object Object { get; private set; }
public ObjectHolder(object obj)
{
this.Object = obj;
}
}
Была ошибка при попытке сериализировать параметр: GetObjectResult. Сообщение InnerException было 'Типом 'Система. Наборы. Универсальный. Словарь' 2 [[Система. Строка, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], [SilverlightApplication7. Сеть. ObjectHolder, SilverlightApplication7. Сеть, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] []' с названием контракта данных 'ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb:http://schemas.microsoft.com/2003/10/Serialization/Arrays' не ожидаются. Добавьте, что любые типы, не известные статически списку известных типов - например, при помощи атрибута KnownTypeAttribute или путем добавления их к списку известных типов, передали DataContractSerializer'.. Дополнительную информацию см. в InnerException.
Снова я играл с ServiceKnownType
для ObjectHolder
, ObjectHolder[]
и даже ObjectHolder[][]
так как исключение упоминает"ArrayOfArrayOfKeyValueOfstringObjectHolder
".
Все еще никакое решение все же.
Попробуйте определить класс, который имеет одно свойство. Это свойство - это словарь строки, объекта.
Отметьте класс с DataconTrtract / DataMember. Затем определите свой интерфейс, используя этот класс.
Прежде всего, вы должны Настроить трассировку WCF в файле приложения COFIG, который может помочь вам понять, что состоится под капотом обслуживания коммуникаций. В этом случае вы можете легко получить все ошибки, возникающие во время процесса связи.
Теперь давайте попробуем решить вашу проблему. Я почти уверен, что проблема в известных типах. В сервисном сервисном мире необходимо вручную определять все конкретные типы, которые могут участвовать в договоре обслуживания, поскольку DataconTractserializer не предоставляет такой информации в сериализованных объектах.
В этом случае это означает, что следует выполнить следующее:
[ServiceKnownType(typeof(string))]
[ServiceKnownType(typeof(Guid))]
[ServiceKnownType(typeof(int))] // but I think DataContractSerializer can deal himself with primitives
[ServiceKnownType(typeof(YourClass))] //UserDefined types you should add manually
public Dictionary<string, object> GetObject()
Также я рекомендовал вам не использовать объект в договоре обслуживания, потому что он очень подвержен ошибкам. Подумайте, что позже вы или один из ваших коллег изменяет одну строку кода:
new Dictionary<string, object>()
{
{ "pty1", 4 },
{ "pty2", Guid.NewGuid() },
{ "pty3", new SomeClass() }, //OOPS!!!
}
в этом случае, когда ваша услуга пытается вернуть этот словарь, вы столкнулись с ошибкой выполнения, поскольку Datacontractserializer не ожидает, что SomeClass в этом договоре не ожидает.
Один из способов решения этой проблемы состоит в том, чтобы создать отдельный тип:
[DataContract]
[KnownType(typeof(Guid))]
[KnownType(typeof(SomeClass1))]
[KnownType(typeof(SomeClass2))]
public class MyType
{
private MyType(object obj) {
Object = obj;
}
public static MyType FromSomeClass1(SomeClass1 c1) {
return new MyType(c1);
}
public static MyType FromSomeClass2(SomeClass2 c2) {
return new MyType(c2);
}
public static MyType FromGuid(Guid guid) {
return new MyType(guid);
}
[DataMember]
public object Object { get; private set; }
}
В этом случае, если вы хотите добавить какой-то новый тип, вы должны добавить фабричный метод и SeveryBeyPeattribute (этот подход более Verbose, но менее ошибка).
Однако, если ваш клиент и сервис, написанные на WCF, вы можете пожертвовать основными сервисными принципами и использовать NetDataContractserializer вместо Datacontractserializer . NetDataContractserializer предназначен для дополнения DataconTractserializer. Вы можете сериализировать тип с использованием NetDataContactserializer и десериализовать с DataContractserializer. Но NetDataconTractserializer включает в себя информацию типа CLR в сериализованном XML, в то время как datacontractserializer не делает. Следовательно, NetDataContractserializer может использоваться при сериализации и десериализации с любыми типами CLR без каких-либо известных вещей.