WCF - Generic List (of T)
-
20-09-2019 - |
Question
I have a list of a custom DTO that I am trying to pass across to a WCF service.
I am getting the following error:
There was an error while trying to serialize parameter tcp://localhost/:oObject. The InnerException message was 'Type 'System.Collections.Generic.List`1[[TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat.HeartBeatDTO, WFCommon, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' with data contract name 'ArrayOfHeartBeatDTO:TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
I have the DTO DataContract and DataMember set. I did an auto WCF service reference, and made sure to do advanced options to change collections to be generic lists instead of array.
What am I missing? Been through a lot of sites that do similar things, but cannot get mine to work past this error. Any ideas?
Code from sender:
<DataContract(Name:="HeartBeatDTO", Namespace:="TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat")> _
Public Class HeartBeatDTO
Public Sub IssuePatientReport()
SBClient.SendCommunication(_PatientID, _HeartBeats)
End Sub
Code at receiver:
Public Sub SendCommunication(ByVal sKey As String, ByVal oObject As Object) Implements iOperatorCommunication.SendCommunication
If _CurrentCommunicationLog.ContainsKey(sKey) Then
_CurrentCommunicationLog.Item(sKey) = oObject
Else
_CurrentCommunicationLog.Add(sKey, oObject)
End If
End Sub
My interface:
<ServiceContract(Namespace:="tcp://localhost/")> _
<ServiceKnownType(GetType(List(Of HeartBeatDTO)))> _
Public Interface iOperatorCommunication
<OperationContract()> _
Function ReceiveCommunication(ByVal sKey As String) As Object
<OperationContract()> _
Function ReturnCommunicationLevel() As Integer
<OperationContract()> _
Function ReturnCommunications() As Dictionary(Of String, Object)
<OperationContract()> _
Function ReturnCommunicationsByKeySearch(ByVal sSearch As String) As Dictionary(Of String, Object)
<OperationContract()> _
Sub SendCommunication(ByVal sKey As String, ByVal oObject As Object)
End Interface
UPDATE: Here is the new error message:
There was an error while trying to serialize parameter tcp://localhost/:oObject. The InnerException message was 'Type 'TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat.HeartBeatDTOList' with data contract name 'HeartBeatDTOList:TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
Solution
If you have custom collection types, you might need to decorate those with a special attribute - see the MSDN docs on CollectionDataContract:
[CollectionDataContract]
public class CustomerList2 : Collection<string> {}
Could that be the problem?
UPDATE: ok, thanks for the posting the interface. I'm no VB.NET expert, but from what I understand and see, you're never actually using the "HeartbeatDTO" type in any of your methods decorated with a OperationContract attribute - right?
So I would imagine you probably also have to define that as a "ServiceKnownType" - try this:
<ServiceContract(Namespace:="tcp://localhost/")> _
<ServiceKnownType(GetType(HeartBeatDTO))> _
<ServiceKnownType(GetType(List(Of HeartBeatDTO)))> _
Public Interface iOperatorCommunication
Does that help?
Also: is there any particular reason you're using "Object" as type throughout your service contract? Couldn't you specify either HeartbeatDTO
or List(Of HeartbeatDTO)
?
UPDATE: could you possibly try - just for the sake of seeing if it works - to create a new service interface list this:
<ServiceContract(Namespace:="tcp://localhost/")> _
Public Interface iOperatorCommunicationStripped
<OperationContract()> _
Sub SendCommunication(ByVal sKey As String, ByVal oObject As List(Of HeartbeatDTO))
End Interface
In this case, your service operation is explicit about its data type and uses a list of HeartbeatDTO objects which are defined as data contracts. If you know create a client proxy for this service contract and call the method - does this work??
Marc