WCF: настройка известных типов - PullRequest
6 голосов
/ 18 февраля 2009

Я хочу знать, как настроить известные типы в WCF. Например, у меня есть класс Person и класс Employee . Класс Employee является подклассом класса Person . Оба класса отмечены атрибутом [DataContract].

Я не хочу жестко кодировать известный тип класса, например помещать [ServiceKnownType(typeof(Employee))] в класс Person, чтобы WCF знал, что Employee является подклассом Person.

Теперь я добавил в файл App.config хоста следующую конфигурацию XML:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
          <knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" />
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
  <system.serviceModel>
    ....... 
  </system.serviceModel>
</configuration>

Я скомпилировал его, запустил хост, добавил ссылку на службу на клиенте, добавил код и запустил клиент. Но произошла ошибка:

Форматировщик выдал исключение, пока пытаясь десериализовать сообщение: Произошла ошибка при попытке параметр десериализации http://www.herbertsabanal.net:person. Сообщение InnerException было «Ошибка в строке 1 позиция 247. Элемент 'http://www.herbertsabanal.net:person' содержит данные 'http://www.herbertsabanal.net/Data:Employee' данные договора. Десериализатор не имеет знание любого типа, который отображается на этот контракт. Добавить тип соответствует «Сотрудник» к список известных типов - например, по используя атрибут KnownTypeAttribute или добавив его в список известных типы переданы DataContractSerializer. ». Посмотри пожалуйста InnerException для более подробной информации.

Ниже приведены данные контрактов:

[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Person")]
    class Person
    {
        string _name;
        int _age;

        [DataMember(Name="Name", Order=0)]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [DataMember(Name="Age", Order=1)]
        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
    }


[DataContract(Namespace="http://www.herbertsabanal.net/Data", Name="Employee")]
    class Employee : Person
    {
        string _id;

        [DataMember]
        public string ID
        {
            get { return _id; }
            set { _id = value; }
        }
    }

Кстати, я не использовал библиотеки классов (библиотеки классов WCF или библиотеки не-WCF) для своей службы. Я просто закодировал это в хост-проекте.

Я полагаю, что проблема в файле конфигурации (см. Файл конфигурации выше). Или я должен что-то упустить. Любая помощь будет очень признательна.

Ответы [ 3 ]

8 голосов
/ 18 февраля 2009

Я думаю, что нашел ответ сейчас.

Файл конфигурации, который я разместил выше, выглядит следующим образом:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Person, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
          <knownType type="Employee, WCFWithNoLibrary, Version=1.0.0.0,Culture=neutral, PublicKeyToken=null" />
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
  <system.serviceModel>
    ....... 
  </system.serviceModel>
</configuration>

Я только что добавил пространство имен класса Person и класса Employee . И нет необходимости в более длинных значениях Version и Culture .... Правильная конфигурация должна быть:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="WCFWithNoLibrary.Person, WCFWithNoLibrary">
          <knownType type="WCFWithNoLibrary.Employee, WCFWithNoLibrary" />
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
  <system.serviceModel>
    ....... 
  </system.serviceModel>
</configuration>

Теперь оно короче и имеет больше смысла. Но если используются сторонние библиотеки, то потребуется добавление version, culture, publickeytokens.

6 голосов
/ 17 марта 2011

Я знаю, что на это уже давно ответили, но есть другое (возможно, более очевидное для будущих программистов) решение:

[KnownType(typeof(SubClass))]
public class BaseClass

Scott

0 голосов
/ 21 апреля 2011

Я получил это длинное сообщение об ошибке и в другом случае. Я использовал KnownTypeAttribute и успешно развернул приложение, которое использует WCF.RIA для производства. Во втором выпуске я добавил новый подтип и добавил необходимый соответствующий KnownTypeAttribute (компилятор не принял его без этого атрибута - отлично). Однако то, что компилятор принял и что запускалось на моей машине, не работало в производстве. Только в производстве я получил ошибку, упомянутую выше. Сравнивая все варианты использования существующих подтипов и нового, я обнаружил, что забыл, что WCF.RIA требует использования имени подтипа в имени метода, такого как GetMySubTypes. Так что, если вы получите эту ошибку после добавления атрибутов, посмотрите, связано ли это с соглашениями WCF.RIA s.

...