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

Solution 1:

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
);

Solution 2:

I had the same issue and some Googling lead me here. I could not accept to have the XMLInclude attribute for each implementation in the base class. I got it to work with a generic serialization method. First off, some of the OP's original example, but slightly modified for clarity:

public abstract class PaymentSummary
{
  public string _summary;
  public string _type;
}

public class xPaymentSummary : PaymentSummary
{
  public xPaymentSummary() { }

  public xPaymentSummary(string summary)
  {
     _summary = summary;
     _type = this.GetType().ToString();
  }
}

In addition to the above, there is also a yPaymentSummary and zPaymentSummary with exactly the same implementation. These are added to a collection, and then the serialization method can be called on each:

List<PaymentSummary> summaries = new List<PaymentSummary>();
summaries.Add(new xPaymentSummary("My summary is X."));
summaries.Add(new yPaymentSummary("My summary is Y."));
summaries.Add(new zPaymentSummary("My summary is Z."));

foreach (PaymentSummary sum in summaries)
  SerializeRecord(sum);

Finally, the serialization method - a simple generic method, that uses the Type of record when serializing:

static void SerializeRecord<T>(T record) where T: PaymentSummary
{
  var serializer = new XmlSerializer(record.GetType());
  serializer.Serialize(Console.Out, record);

  Console.WriteLine(" ");
  Console.WriteLine(" ");
}

The above yields the following output:

enter image description here