Сервис WCF, возвращая массив словаря <строка, объект>

Я пытался использовать клиент 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".

Все еще никакое решение все же.

6
задан shA.t 31 May 2015 в 10:55
поделиться

2 ответа

Попробуйте определить класс, который имеет одно свойство. Это свойство - это словарь строки, объекта.

Отметьте класс с DataconTrtract / DataMember. Затем определите свой интерфейс, используя этот класс.

0
ответ дан 16 December 2019 в 21:40
поделиться

Прежде всего, вы должны Настроить трассировку 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 без каких-либо известных вещей.

8
ответ дан 16 December 2019 в 21:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: