WCF сериализует объекты с наследованием

#wcf #serialization #inheritance

#wcf #сериализация #наследование

Вопрос:

Вот что я пытаюсь сделать. У меня есть служба WCF restful, и мне нужно сериализовать несколько объектов, которые наследуются от одного и того же класса.

Ни в одном из базовых классов нет ничего, что нужно сериализовать.

Вот минимальная демонстрация, которая показывает, что я хочу заставить работать:

 <DataContract()>
Public Class BaseObj

    <DataMember()>
    Public ID As Integer

    Public Sub New(ByVal idval As Integer)
        ID = idval
    End Sub

End Class

<DataContract()>
Public Class TestObj1
    Inherits BaseObj

    Public Sub New(ByVal id As Integer)
        MyBase.New(id)
    End Sub

End Class

' Different from TestObj1 in real life
<DataContract()>
Public Class TestObj2
    Inherits BaseObj

    Public Sub New(ByVal id As Integer)
        MyBase.New(id)
    End Sub

End Class
  

И вот код, который это использует:

 <ServiceContract()>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerCall)>
Public Class Service1

    <WebGet(ResponseFormat:=WebMessageFormat.Json, UriTemplate:="Test?reqReportID={reqReportID}")>
    Public Function GetCollection(ByVal reqReportID As Integer) As List(Of BaseObj)

        Dim myObjs As New List(Of BaseObj)
        myObjs.Add(New TestObj1(20))
        myObjs.Add(New TestObj2(20))
        Return myObjs

    End Function

End Class
  

Если вместо этого я объявляю список списком TestObj1 , все работает.

Я упускаю здесь какую-то важную концепцию?

Редактировать:

Проблема приобретает новый уровень путаницы при просмотре этого кода:

     <WebGet(ResponseFormat:=WebMessageFormat.Json, UriTemplate:="Test?reqReportID={reqReportID}")>
    Public Function GetCollection(ByVal reqReportID As Integer) As BaseObj()

        Dim myObjs As New List(Of BaseObj)
        myObjs.Add(New TestObj1(20))
        myObjs.Add(New TestObj2(20))

        '   This guy works. Yields correct result of [{"ID":20},{"ID":20}] )
        Dim testStr As String = New JavaScriptSerializer().Serialize(myObjs.ToArray())

        '   But this guy still has problems...
        Return myObjs.ToArray()

    End Function
  

Ответ №1:

Чего вам не хватает, так это [KnownType] атрибута.

WCF требует способа знать все возможные типы, чтобы он мог публиковать WSDL.

Взгляните сюда.

Обновить

Проблема в том, что это List<T> не ковариантно.

Используйте IEnumerable<T> вместо этого.

Комментарии:

1. Неплохое предложение, но если я изменю строку <DataContract()> на <DataContract(),KnownType(GetType(BaseObj))> для обоих TestObj1 и TestObj2 , поведение останется неизменным. Проблема в том, что я добавляю это неправильно?

2. Извините, я обновил свой ответ. Я заметил, что вам не нужен KnownType

3. @Aliostad, я действительно ценю ваш вклад, однако у меня все еще не получается заставить его работать. Я изменил возвращаемый тип на простой массив, и он по-прежнему ведет себя так же. Чтобы еще больше запутать ситуацию, я могу вручную сериализовать массив, это работает просто отлично (см. Правки к вопросу).

4. Массив также не всегда ковариантен. Я обновил свой ответ. Используйте IEnumerable<T> , и это должно сработать.

5. @Aliostad, я не уверен, что это объясняет причину, потому что сериализация вручную действительно работает. Изменение возвращаемого типа на IEnumerable(Of BaseObj) , похоже, вообще не изменило поведение.