Настройка
У меня есть служба WCF, которая предоставляет базовый тип (например, животное), а также несколько производных типов (например, лев, тигр и медведь). Другой тип (например, Zoo) включает свойство, которое является коллекцией базового типа. Базовый тип является конкретным, не абстрактным, поэтому для коллекции вполне допустимо содержать экземпляры базового типа и/или производных типов (в любой комбинации). Например:
[DataContract, KnownType(typeof(Lion)),
KnownType(typeof(Tiger)), KnownType(typeof(Bear))]
public class Animal
{
[DataMember]
public string Species { get; set; }
}
[DataContract]
public class Lion : Animal { }
[DataContract]
public class Tiger : Animal { }
[DataContract]
public class Bear : Animal { }
[DataContract]
public class Zoo
{
[DataMember]
public List<Animal> Animals { get; set; }
}
Одна из моих сервисных операций принимает этот тип в качестве параметра, например:
[ServiceContract]
public interface IZooService
{
[OperationContract]
void SetZoo(Zoo zoo);
}
Все это хорошо, и сгенерированный WSDL выглядит для меня совершенно нормально. Он содержит все типы и правильно указывает, что производные типы наследуются от базового типа. Итак, я должен иметь возможность вызывать свою службу, используя сообщение SOAP, например следующее:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:z="http://zoo.org">
<soapenv:Header/>
<soapenv:Body>
<z:SetZoo>
<z:Zoo>
<z:Animals>
<z:Animal>
<z:Species>Crocodile</z:Species>
</z:Animal>
<z:Tiger>
<z:Species>Bengal</z:Species>
</z:Tiger>
<z:Bear>
<z:Species>Grizzly</z:Species>
</z:Bear>
</z:Animals>
</z:Zoo>
</z:SetZoo>
</soapenv:Body>
</soapenv:Envelope>
В приведенном выше сообщении SOAP коллекция Animals содержит один экземпляр базового типа Animal, экземпляр производного типа Tiger и экземпляр производного типа Bear. WCF должен иметь возможность успешно десериализовать это сообщение.
Проблема
WCF не генерирует никаких исключений, когда получает указанное выше сообщение. Вместо этого он просто полностью игнорирует производные типы (Tiger и Bear), и к тому времени, когда десериализованное сообщение передается моему коду, коллекция Animals содержит только запись Crocodile, поскольку она относится к базовому типу.
Итак, у меня есть два вопроса... Во-первых, почему WCF не десериализует экземпляры производных типов в коллекции. И, во-вторых, поскольку WCF явно что-то не нравится в этом SOAP-сообщении, почему он не генерирует исключение? Такого рода тихий провал очень беспокоит.