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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With