11/5/12

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


When trying to serialize a complex object using the XmlSerializer, we can encountered a Type was not expected exception. This exception is generated as a result of a property declared as a base type, but the actual reference is done with a child class instance. For example:

Class Declaration:

public class Account
{
int number { get; set; }
}

public class Client
{
public object[] Accounts { get; set; }
}

The client class has an array of Accounts, but the declaration of the property uses object instead of the Account class. When we try to serialize an instance of Client with the code below, the exception is generated:

Client client = new Client();
client.Accounts = new Account[]{new Account(), new Account()};

StringBuilder stringBuilder = new StringBuilder();
           
 using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
 {
          XmlSerializer serializer = new XmlSerializer(typeof(Client));
          serializer.Serialize(xmlWriter, objRef); 
           xmlWriter.Flush();
  }

InnerException      {"The type Account was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."} System.Exception {System.InvalidOperationException}

Solution:


The serializer expects a type of object, but it finds a type of Account instead. The easy fix would be to refactor the property and use Account instead of object. This is not as easy when we do not have access to the source code as in the case when using a third party API. When this is the case, we can tell the serializer to expect unknown types by including an array of types when instantiating the XmlSerializer which provides the following constructor:

public XmlSerializer(
                   Type type,
                   Type[] extraTypes
)

We can now change the previous code with the following:

Client client = new Client();
client.Accounts = new Account[]{new Account(), new Account()};
Type[] types = new Type[] { typeof(Account)};

StringBuilder stringBuilder = new StringBuilder();
           
  using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
  {
                 XmlSerializer serializer = new XmlSerializer(typeof(Client),types);
                 serializer.Serialize(xmlWriter, objRef); 
                 xmlWriter.Flush();
 }

We are now creating an array of Type[] and passing that information to the serializer in its constructor. If you run this code, you can now notice that the exception is no longer raised.  We should also notice that there may be other properties with this problem. When this is the case, we need to include all those types in the array as follows:

Type[] types = new Type[] { typeof(Account), typeof(Address)};

In this case, we added the Address type as another possible type which should be included during the serialization.

I hope I was able to help you understand why this exception is raised when serializing complex objects and show you a way to handle the problem.