views:

986

answers:

1

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.

+3  A: 

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

marc_s
Wow... that certainly looks like what I need... do I add that as a new class, or modify my DTO class to use that DataContract instead of the current?
IPX Ares
Nevermind... did not read far enough, looks like a separate class. Let me try that out.
IPX Ares
Here is what I added: <CollectionDataContract()> _ Public Class HeartBeatList Inherits List(Of HeartBeatDTO) End Class ... But that did not seem to do it... I also tried to update the service contract:<ServiceKnownType(GetType(HeartBeatList))> _
IPX Ares
I actually really wanted the service to be type ignorant, which is why I left the interface as an object. I did try changing the interface as well, but that did not seem to help.
IPX Ares
I am still getting the same error... even though I tried all of that. No idea (doublechecked the service reference as well) where it is getting: "with data contract name 'ArrayOfHeartBeatDTO:http://schemas.datacontract.org/2004/07/TEGE.ER.WorkFlowEngine.WFCommon.HeartBeat' is not expected."
IPX Ares
@IPXAres: the approach leaving the service "type ignorant" is a good idea in OOP terms - but SOA world is quite different. Since client+server only communicate over messages, both need to be able to serialize and deserialize the messages, and thus must **know** what they're dealing with. So anything going back and forth must be expressed in XML schema and thus you can really only ever use concrete types.
marc_s
After you've changed the service definition on the server, did you recreate the client proxy class?
marc_s