I've seen many users in blogs and forums around the web facing several dificulties when it comes to to webservices and encoded SOAP/XML data types. In a client application that references a web service, there might be occasions when you need to use a derived object that is defined on your web service assemblies, but isn't directly available to your application. This is because the Web Services Discovery Tool (Disco.exe) that generates code for XML Web services and XML Web service clients only serializes objects that are directly or indirectly used in its web method signatures.

Just as a reminder: the Web Services Discovery tool finds the URLs of XML Web services on a Web server and generates documents related to each XML Web service locally. Such documents are .wsdl, .xsd, .disco, and .discomap files. 

So in order to include derived classes in service description documents (and only this kind. Loose classes aren't caught by the XMLSerializer), there are actually two paths we can follow. One is by using the XMLInclude attribute, and the other is it's close parent, SOAPAttribute. By specifying these attributes on a web service webmethod or class, and by giving them a type parameter, we are allowing the XmlSerializer to recognize that same type when it serializes or deserializes our web service class. The difference between these two attributes is that SOAPInclude assumes serialization as encoded SOAP XML and by this we conclude there are some rules to follow regarding SOAP 1.1. Also, SoapInclude will only work if its used on RPC/Encoded services. Remember this. There are a lot of people with this issue and mostly due to incomplete information on this matter. The default for ASP.NET is to use document/literal encoding witch is recommended.

The following code illustrates this approach:

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Web;

    5 using System.Web.Services;

    6 

    7 namespace Demo

    8 {

    9     /// <summary>

   10     /// ExampleWebService is a demo code for article purposes

   11     /// </summary>

   12     [WebService(Namespace = "http://tempuri.org/")]

   13     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

   14     [System.ComponentModel.ToolboxItem(false)]

   15     public class ExampleWebService : System.Web.Services.WebService

   16     {

   17 

   18         [WebMethod]

   19         public Person WhoAmI()

   20         {

   21             Person p = new Person();

   22             p.Age = 27;

   23             p.Name = "Vasco Oliveira";

   24             return p;

   25         }

   26     }

   27 

   28     public class Person

   29     {

   30         private string _Name;

   31         public string Name

   32         {

   33             get { return _Name; }

   34             set { _Name = value; }

   35         }

   36         private short _age;

   37         public short Age

   38         {

   39             get { return _age; }

   40             set { _age = value; }

   41         }

   42     }

   43 

   44     public class Employee : Person

   45     {

   46         private Person _person;

   47         public Person Person

   48         {

   49             get { return _person; }

   50             set { _person = value; }

   51         }

   52         private short _type;

   53         public short Type

   54         {

   55             get { return _type; }

   56             set { _type = value; }

   57         }

   58     }

   59 }

When this web service class serialized into its wsdl file using Disco.exe, it only renders:

<s:complexType name="Person">
    <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string" />
        <s:element minOccurs="1" maxOccurs="1" name="Age" type="s:short" />
    </s:sequence>
</s:complexType>

 And the wsdl.exe generated code file Resource.cs will only have:

    1 public partial class Person {

    2 

    3         private string nameField;

    4 

    5         private short ageField;

    6 

    7         /// <remarks/>

    8         public string Name {

    9             get {

   10                 return this.nameField;

   11             }

   12             set {

   13                 this.nameField = value;

   14             }

   15         }

   16 

   17         /// <remarks/>

   18         public short Age {

   19             get {

   20                 return this.ageField;

   21             }

   22             set {

   23                 this.ageField = value;

   24             }

   25         }

   26     }

So by adding XMLInclude to the web service class header like this:

[XmlInclude(typeof(Employee))]

public class ExampleWebService : System.Web.Services.WebService

And re-generating the wsdl file and Reference.cs file (Disco.exe and wsdl.exe), we'll then get the Employee class perfectly defined in our proxy class:

<s:complexType name="Employee">
    <s:complexContent mixed="false">
        <s:extension base="tns:Person">
            <s:sequence>
                <s:element minOccurs="0" maxOccurs="1" name="Person" type="tns:Person" />
                <s:element minOccurs="1" maxOccurs="1" name="Type" type="s:short" />
            </s:sequence>
        </s:extension>
    </s:complexContent>
</s:complexType>

... and in our generated class:

    1 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3031")]

    2     [System.SerializableAttribute()]

    3     [System.Diagnostics.DebuggerStepThroughAttribute()]

    4     [System.ComponentModel.DesignerCategoryAttribute("code")]

    5     [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]

    6     public partial class Employee : Person {

    7 

    8         private Person person1Field;

    9 

   10         private short typeField;

   11 

   12         /// <remarks/>

   13         [System.Xml.Serialization.XmlElementAttribute("Person")]

   14         public Person Person1 {

   15             get {

   16                 return this.person1Field;

   17             }

   18             set {

   19                 this.person1Field = value;

   20             }

   21         }

   22 

   23         /// <remarks/>

   24         public short Type {

   25             get {

   26                 return this.typeField;

   27             }

   28             set {

   29                 this.typeField = value;

   30             }

   31         }

   32     }

 It's this simple.