Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
464 views
in Technique[技术] by (71.8m points)

c# - Is there a reason why a base class decorated with XmlInclude would still throw a type unknown exception when serialized?

I will simplify the code to save space but what is presented does illustrate the core problem.

I have a class which has a property that is a base type. There are 3 derived classes which could be assigned to that property.

If I assign any of the derived classes to the container and attempt to serialize the container, the XmlSerializer throws the dreaded:

"The type x was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."

However my base class is already decorated with that attribute so I figure there must be an additional "hidden" requirement.

The really odd part is that the default WCF serializer has no issues with this class hierarchy.

The Container class

[DataContract]
[XmlRoot(ElementName = "TRANSACTION", Namespace = Constants.Namespace)]
public class PaymentSummaryRequest : CommandRequest
{
    [DataMember]
    public PaymentSummary Summary { get; set; }

    public PaymentSummaryRequest()
    {
        Mechanism = CommandMechanism.PaymentSummary;
    }
}

The base class

[DataContract]
[XmlInclude(typeof(xPaymentSummary))]
[XmlInclude(typeof(yPaymentSummary))]
[XmlInclude(typeof(zPaymentSummary))]
[KnownType(typeof(xPaymentSummary))]
[KnownType(typeof(yPaymentSummary))]
[KnownType(typeof(zPaymentSummary))]
public abstract class PaymentSummary
{     
}

One of the derived classes

[DataContract]
public class xPaymentSummary : PaymentSummary
{
}

The serialization code

var serializer = new XmlSerializer(typeof(PaymentSummaryRequest));
serializer.Serialize(Console.Out,new PaymentSummaryRequest{Summary = new xPaymentSummary{}});

The Exception

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type xPaymentSummary was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically. at

Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write13_PaymentSummary(String n, String ns, PaymentSummary o, Boolean isNullable, Boolean needType) at

Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write14_PaymentSummaryRequest(String n, String ns, PaymentSummaryRequest o, Boolean isNullable, Boolean needType) at

Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write15_TRANSACTION(Object o) --- End of inner exception stack trace --- at

System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) at

System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
at UserQuery.RunUserAuthoredQuery() in c:UsersTedfordAppDataLocalTempuqacncyo.0.cs:line 47

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The issue you are seeing is because the PaymentSummaryRequest is setting the Namespace. You can either remove the Namespace or add a Namespace to the PaymentSummary class:

[XmlRoot(Namespace = Constants.Namespace)]
[XmlInclude(typeof(xxxPaymentSummary))]
public abstract class PaymentSummary
{
}

As @Tedford mentions in his comment below the namespace is only required when using derived types.

It looks like when generating the XML Serialization assembly that since the Root node has a namespace set and the base class does not it is not including the XML Include logic in the generated serialization assembly.

Another approach to solving the issue would be to remove the namespace declarations from the classes themselves and specify the namespace on the XmlSerializer constructor:

var serializer = new XmlSerializer(
    typeof(PaymentSummaryRequest), 
    Constants.Namespace
);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...