Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF Abstract base class with complex collection of abstract types not being included for deserialization in service response

We are using a base class for all of our Response DTO's in our application. The class has the following signature:

[Serializable]
public abstract class ResponseBase
{
    public bool Successful { get; set; }
    public List<ResponseMessage> Messages { get; set; }

    //...Other code...
}

The Messages collection can be any of the following types:

[Serializable]
[XmlInclude(typeof(DebugMessage))]
[XmlInclude(typeof(InfoMessage))]
[XmlInclude(typeof(ValidationMessage))]
[XmlInclude(typeof(WarnMessage))]
[XmlInclude(typeof(RecoverableFaultMessage))]
[XmlInclude(typeof(FatalFaultMessage))]
public abstract class ResponseMessage
{
    //..Other code...
}

With concrete versions of:

[Serializable]
public class DebugMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.Debug; } }
}
[Serializable]
public class InfoMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.Info; } }
}
[Serializable]
public class ValidationMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.Validation; } }
}
[Serializable]
public class WarnMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.Warn; } }
}
[Serializable]
public class RecoverableFaultMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.RecoverableFault; } }
}
[Serializable]
public class FatalFaultMessage : ResponseMessage
{
    public override MessageType MessageType { get { return MessageType.FatalFault; } }
}

All DTO Response objects inherit from ResponseBase however even with the following ServiceKnownTypes on the WCF Contract

[ServiceKnownType(typeof(ResponseBase))]
[ServiceKnownType(typeof(ResponseMessage))]
[ServiceKnownType(typeof(List<ResponseMessage>))]
[ServiceKnownType(typeof(DebugMessage))]
[ServiceKnownType(typeof(InfoMessage))]
[ServiceKnownType(typeof(ValidationMessage))]
[ServiceKnownType(typeof(WarnMessage))]
[ServiceKnownType(typeof(RecoverableFaultMessage))]
[ServiceKnownType(typeof(FatalFaultMessage))]
[ServiceKnownType(typeof(List<DebugMessage>))]
[ServiceKnownType(typeof(List<InfoMessage>))]
[ServiceKnownType(typeof(List<ValidationMessage>))]
[ServiceKnownType(typeof(List<WarnMessage>))]
[ServiceKnownType(typeof(List<RecoverableFaultMessage>))]
[ServiceKnownType(typeof(List<FatalFaultMessage>))]

When we load a Message into the ResponseBase Messages collection the following exception gets thrown:

Error in line 1 position 906. Element 'http://schemas.datacontract.org/2004/07/CX.Framework.Common.BaseTypes:ResponseMessage' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/CX.Framework.Common.BaseTypes:WarnMessage'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'WarnMessage' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.

We have done everything from ServiceKnownType to XMLInclude on the derived types. I'm at a bit of a loss as to how to resolve this and would appreciate any assistance anyone can provide.

like image 995
VulgarBinary Avatar asked Dec 20 '12 16:12

VulgarBinary


1 Answers

A few things:

1) [XmlInclude] will have no effect on the DataContractSerializer, it's only used by the XmlSerializer.

2) As the commenter "flem" suggested, I would use [KnownType] directly on ResponseMessage instead of [ServiceKnownType] on the service.

3) I don't remember whether the DataContractSerializer even looks for [KnownType] on [Serializable] types. At least for testing purposes for now, try making your types [DataContract] instead (and attribute the data members with [DataMember]) if #2 above doesn't help.

like image 55
Eugene Osovetsky Avatar answered Sep 27 '22 21:09

Eugene Osovetsky