#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)
, похоже, вообще не изменило поведение.