Click to Rate and Give Feedback
Collapse All/Expand All Collapse All
This page is specific to
Microsoft Visual Studio 2008/.NET Framework 3.5

Other versions are also available for the following:
.NET Framework Class Library
IDataContractSurrogate Interface

Provides the methods needed to substitute one type for another by the DataContractSerializer during serialization, deserialization, and export and import of XML schema documents (XSD).

Namespace:  System.Runtime.Serialization
Assembly:  System.Runtime.Serialization (in System.Runtime.Serialization.dll)
Visual Basic (Declaration)
Public Interface IDataContractSurrogate
Visual Basic (Usage)
Dim instance As IDataContractSurrogate
C#
public interface IDataContractSurrogate
Visual C++
public interface class IDataContractSurrogate
JScript
public interface IDataContractSurrogate

Use the IDataContractSurrogate when using the DataContractSerializer if you need to do one of the following: substitute one type or object for another, or to dynamically generate schema variations. For a sample application, see DataContract Surrogate Sample. For more information about data contracts, see Using Data Contracts.

At run time, you can find the specific DataContractSerializer for any operation in a service by using the OperationDescription to find the DataContractSerializerOperationBehavior instance. For more information about implementing the interface to create a surrogate, see Data Contract Surrogates.

You can also use the IDataContractSurrogate to affect the import and export of XML schemas when you are using the XsdDataContractExporter and XsdDataContractImporter classes. You can do so by assigning the IDataContractSurrogate to the DataContractSurrogate property of the ExportOptions class, or to the DataContractSurrogate property of the ImportOptions class. For more information, see Schema Import and Export.

The following example shows an implementation of the IDataContractSurrogate interface. The code substitutes the serialization of the Person type for a PersonSurrogated class.

Visual Basic
Class Program

    Shared Sub Main(ByVal args() As String) 
        ' Create and populate an Employee instance.
        Dim emp As New Employee()
        emp.date_hired = New DateTime(1999, 10, 14)
        emp.salary = 33000

        ' Note that the Person class is a legacy XmlSerializable class
        ' without a DataContract.
        emp.person = New Person()
        emp.person.first_name = "Mike"
        emp.person.last_name = "Ray"
        emp.person.age = 44

        ' Create a serializer.
        Dim ser As New DataContractSerializer(GetType(Employee))

        ' Attempt to serialize without a surrogate. (This will fail.)
        Console.WriteLine(" Attempting to serialize without a surrogate: " + vbLf)
        Dim fileName As String = "surrogateEmployee.xml"
        Dim fs As New FileStream(fileName, FileMode.Create)
        Dim writer As XmlDictionaryWriter = XmlDictionaryWriter.CreateTextWriter(fs)
        Try
            ser.WriteObject(writer, emp)
            writer.Flush()
            writer.Close()
        Catch 
            writer.Flush()
            Console.Write(writer.ToString())
            Console.WriteLine(vbLf + vbLf + _
          " Cannot serialize without a surrogate since Person has no DataContract " + vbLf)
        End Try
        ' Close the writer objects after failing to serialize.
        writer.Close()
        fs.Close()

        Console.WriteLine(" Now use a surrogate for the Person class and try again")
        ' Create a new instance of the serializer. The 
        ' constructor demands a knownTypes and surrogate. 
        ' Create a Generic List for the knownTypes. Then create an
        ' instance of the surrogate class (defined below).
        Dim knownTypes As List(Of Type) = New List(Of Type)()
        Dim sur As New LegacyPersonTypeSurrogate()
        Dim surrogateSerializer As New _
        DataContractSerializer(GetType(Employee), _
           knownTypes, Integer.MaxValue, False, True, sur)

        ' Create a new writer. Then serialize with the 
        ' surrogate serializer.
        Dim newFs As New FileStream(fileName, FileMode.Create)
        Dim newWriter As XmlDictionaryWriter = XmlDictionaryWriter.CreateTextWriter(newFs)
        Try
            surrogateSerializer.WriteObject(newWriter, emp)
            Console.Write(newWriter.ToString())
            Console.WriteLine("Serialization succeeded. Now doing deserialization.")
            newWriter.Close()
            newFs.Close()
        Catch 
            Console.WriteLine(" We never get here")
        End Try

        ' Create a new reader object.
        Dim fs2 As New FileStream(fileName, FileMode.Open)
        Dim reader As XmlDictionaryReader = _
            XmlDictionaryReader.CreateTextReader(fs2, New XmlDictionaryReaderQuotas())

        Console.WriteLine("Trying to deserialize with surrogate.")
        Try
            Dim newemp As Employee = CType _
                (surrogateSerializer.ReadObject(reader, False), Employee)

            reader.Close()
            fs2.Close()

            Console.WriteLine("Deserialization succeeded. " + vbLf + vbLf)
            Console.WriteLine("Deserialized Person data: " + vbLf + vbTab + _
                " {0} {1}", newemp.person.first_name, newemp.person.last_name)
            Console.WriteLine(vbTab + " Age: {0} " + vbLf, newemp.person.age)

        Catch serEx As SerializationException
            Console.WriteLine(serEx.Message)
            Console.WriteLine(serEx.StackTrace)
        End Try

        Console.WriteLine("Now doing schema export/import.")

        ' The following code demonstrates schema export with a surrogate.
        ' The surrogate indicates how to export the non-DataContract Person type.
        ' Without the surrogate, schema export would fail.
        Dim xsdexp As New XsdDataContractExporter()
        xsdexp.Options = New ExportOptions()
        xsdexp.Options.DataContractSurrogate = New LegacyPersonTypeSurrogate()
        xsdexp.Export(GetType(Employee))

        ' Write out the exported schema to a file.
        Dim fs3 As New FileStream("sample.xsd", FileMode.Create)
        Try
            Dim sch As XmlSchema
            For Each sch In xsdexp.Schemas.Schemas()
                sch.Write(fs3)
            Next sch
        Finally
            fs3.Dispose()
        End Try

        ' The following code demonstrates schema import with 
        ' a surrogate. The surrogate is used to indicate that 
        ' the Person class already exists and that there is no 
        ' need to generate a new class when importing the
        ' PersonSurrogated data contract. If the surrogate 
        ' was not used, schema import would generate a 
        ' PersonSurrogated class, and the person field 
        ' of Employee would be imported as 
        ' PersonSurrogated and not Person.
        Dim xsdimp As New XsdDataContractImporter()
        xsdimp.Options = New ImportOptions()
        xsdimp.Options.DataContractSurrogate = New LegacyPersonTypeSurrogate()
        xsdimp.Import(xsdexp.Schemas)

        ' Write out the imported schema to a C-Sharp file.
        Dim fs4 As FileStream = New FileStream("sample.cs", FileMode.Create)
        Try
            Dim tw As New StreamWriter(fs4)
            Dim cdp As New Microsoft.CSharp.CSharpCodeProvider()
            cdp.GenerateCodeFromCompileUnit(xsdimp.CodeCompileUnit, tw, Nothing)
            tw.Flush()
        Finally
            fs4.Dispose()
        End Try

        Console.WriteLine(vbLf + " To see the results of schema export and import,")
        Console.WriteLine(" see SAMPLE.XSD and SAMPLE.CS." + vbLf)

        Console.WriteLine(" Press ENTER to terminate the sample." + vbLf)
        Console.ReadLine()

    End Sub 
End Class 


' This is the Employee (outer) type used in the sample.

<DataContract()>  _
Class Employee
    <DataMember()>  _
    Public date_hired As DateTime

    <DataMember()>  _
    Public salary As [Decimal]

    <DataMember()>  _
    Public person As Person
End Class 


' This is the Person (inner) type used in the sample.
' Note that it is a legacy XmlSerializable type and not a DataContract type.

Public Class Person
    <XmlElement("FirstName")>  _
    Public first_name As String

    <XmlElement("LastName")>  _
    Public last_name As String

    <XmlAttribute("Age")>  _
    Public age As Integer


    Public Sub New() 

    End Sub 
End Class 

' This is the surrogated version of the Person type
' that will be used for its serialization/deserialization.

<DataContract()>  _
Class PersonSurrogated

    ' xmlData will store the XML returned for a Person instance 
    ' by the XmlSerializer.
    <DataMember()>  _
    Public xmlData As String

End Class 



' This is the surrogate that substitutes PersonSurrogated for Person.

Class LegacyPersonTypeSurrogate 
Implements IDataContractSurrogate

    Public Function GetDataContractType(ByVal type As Type) As Type _
       Implements IDataContractSurrogate.GetDataContractType

        ' "Person" will be serialized as "PersonSurrogated"
        ' This method is called during serialization,
        ' deserialization, and schema export.
        If GetType(Person).IsAssignableFrom(type) Then
            Return GetType(PersonSurrogated)
        End If
        Return type

    End Function 

    Public Function GetObjectToSerialize(ByVal obj As Object, _
        ByVal targetType As Type) As Object _
        Implements IDataContractSurrogate.GetObjectToSerialize

        ' This method is called on serialization.
        ' If Person is not being serialized...
        If TypeOf obj Is Person Then
            ' ... use the XmlSerializer to perform the actual serialization.
            Dim ps As New PersonSurrogated()
            Dim xs As New XmlSerializer(GetType(Person))
            Dim sw As New StringWriter()
            xs.Serialize(sw, CType(obj, Person))
            ps.xmlData = sw.ToString()
            Return ps
        End If
        Return obj

    End Function     

    Public Function GetDeserializedObject(ByVal obj As Object, _
        ByVal targetType As Type) As Object Implements _
        IDataContractSurrogate.GetDeserializedObject

        ' This method is called on deserialization.
        ' If PersonSurrogated is not being deserialized...
        If TypeOf obj Is PersonSurrogated Then
            '... use the XmlSerializer to do the actual deserialization.
            Dim ps As PersonSurrogated = CType(obj, PersonSurrogated)
            Dim xs As New XmlSerializer(GetType(Person))
            Return CType(xs.Deserialize(New StringReader(ps.xmlData)), Person)
        End If
        Return obj

    End Function     

    Public Function GetReferencedTypeOnImport(ByVal typeName As String, _
        ByVal typeNamespace As String, ByVal customData As Object) As Type _
        Implements IDataContractSurrogate.GetReferencedTypeOnImport

        ' This method is called on schema import.
        ' If a PersonSurrogated data contract is 
        ' in the specified namespace, do not create a new type for it 
        ' because there is already an existing type, "Person".

        If typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample") Then
            If typeName.Equals("PersonSurrogated") Then
                Return GetType(Person)
            End If
        End If
        Return Nothing

    End Function     

    Public Function ProcessImportedType(ByVal typeDeclaration _
        As System.CodeDom.CodeTypeDeclaration, _
        ByVal compileUnit As System.CodeDom.CodeCompileUnit) _
        As System.CodeDom.CodeTypeDeclaration _
    Implements IDataContractSurrogate.ProcessImportedType

        ' Not used in this sample.
        ' You could use this method to construct an entirely new CLR 
        ' type when a certain type is imported, or modify a 
        ' generated type in some way.
        Return typeDeclaration
    End Function 


    Overloads Public Function GetCustomDataToExport _
        (ByVal clrType As Type, ByVal dataContractType As Type) As Object _
        Implements IDataContractSurrogate.GetCustomDataToExport

        ' Not used in this sample
        Return Nothing    
    End Function 


    Overloads Public Function GetCustomDataToExport _
       (ByVal memberInfo As System.Reflection.MemberInfo, _
       ByVal dataContractType As Type) As Object _
        Implements IDataContractSurrogate.GetCustomDataToExport

        ' Not used in this sample
        Return Nothing

    End Function 


    Public Sub GetKnownCustomDataTypes(ByVal customDataTypes As Collection(Of Type)) _
 Implements IDataContractSurrogate.GetKnownCustomDataTypes

        ' Not used in this sample

    End Sub
End Class 
C#
class Program
{
    static void Main(string[] args)
    {
        // Create and populate an Employee instance.
        Employee emp = new Employee();
        emp.date_hired = new DateTime(1999, 10, 14);
        emp.salary = 33000;

        // Note that the Person class is a legacy XmlSerializable class
        // without a DataContract.
        emp.person = new Person();
        emp.person.first_name = "Mike";
        emp.person.last_name = "Ray";
        emp.person.age = 44;

        // Create a serializer.
        DataContractSerializer ser =
            new DataContractSerializer(typeof(Employee));

        // Attempt to serialize without a surrogate. (This will fail.)
        Console.WriteLine(" Attempting to serialize without a surrogate: \n");
        string fileName = "surrogateEmployee.xml";
        FileStream fs = new FileStream(fileName, FileMode.Create);
        XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
        try
        {
            ser.WriteObject(writer, emp);
            writer.Flush();
            writer.Close();
        }
        catch (InvalidDataContractException)
        {
            writer.Flush();
            Console.Write(writer.ToString());
            Console.WriteLine("\n\n Cannot serialize without a surrogate since Person has no DataContract \n");
        }
        // Close the writer objects after failing to serialize.
        writer.Close();
        fs.Close();

        Console.WriteLine
            (" Now use a surrogate for the Person class and try again");
        // Create a new instance of the serializer. The 
        // constructor demands a knownTypes and surrogate. 
        // Create a Generic List for the knownTypes. Then create an
        // instance of the surrogate class (defined below).
        List<Type> knownTypes = new List<Type>();
        LegacyPersonTypeSurrogate sur =
            new LegacyPersonTypeSurrogate();
        DataContractSerializer surrogateSerializer =
            new DataContractSerializer(typeof(Employee), knownTypes,
            int.MaxValue /*maxItemsInObjectGraph */, false /*ignoreExtensionDataObject*/
            , true /*preserveObjectReferences*/, sur);

        // Create a new writer. Then serialize with the 
        // surrogate serializer.
        FileStream newFs = new FileStream(fileName, FileMode.Create);
        XmlDictionaryWriter newWriter = XmlDictionaryWriter.CreateTextWriter(newFs);
        try
        {
            surrogateSerializer.WriteObject(newWriter, emp);
            Console.Write(newWriter.ToString());
            Console.WriteLine("Serialization succeeded. Now doing deserialization.");
            newWriter.Close();
            newFs.Close();
        }
        catch (InvalidDataContractException)
        {
            Console.WriteLine(" We never get here");
        }

        // Create a new reader object.
        FileStream fs2 = new FileStream(fileName, FileMode.Open);
        XmlDictionaryReader reader = XmlDictionaryReader.
            CreateTextReader(fs2, new XmlDictionaryReaderQuotas());

        Console.WriteLine("Trying to deserialize with surrogate.");
        try
        {
            Employee newemp = (Employee)surrogateSerializer.ReadObject(reader, false);
            reader.Close();
            fs2.Close();
            Console.WriteLine("Deserialization succeeded. \n\n");
            Console.WriteLine("Deserialized Person data: \n\t {0} {1}",
                newemp.person.first_name, newemp.person.last_name);
            Console.WriteLine("\t Age: {0} \n", newemp.person.age);
        }
        catch (SerializationException serEx)
        {
            Console.WriteLine(serEx.Message);
            Console.WriteLine(serEx.StackTrace);
        }

        Console.WriteLine("Now doing schema export/import.");
        // The following code demonstrates schema export with a surrogate.
        // The surrogate indicates how to export the non-DataContract Person type.
        // Without the surrogate, schema export would fail.
        XsdDataContractExporter xsdexp = new XsdDataContractExporter();
        xsdexp.Options = new ExportOptions();
        xsdexp.Options.DataContractSurrogate = new LegacyPersonTypeSurrogate();
        xsdexp.Export(typeof(Employee));

        // Write out the exported schema to a file.
        using (FileStream fs3 = new FileStream("sample.xsd", FileMode.Create))
        {
            foreach (XmlSchema sch in xsdexp.Schemas.Schemas())
            {
                sch.Write(fs3);
            }
        }

        // The following code demonstrates schema import with 
        // a surrogate. The surrogate is used to indicate that 
        // the Person class already exists and that there is no 
        // need to generate a new class when importing the
        // PersonSurrogated data contract. If the surrogate 
        // was not used, schema import would generate a 
        // PersonSurrogated class, and the person field 
        // of Employee would be imported as 
        // PersonSurrogated and not Person.
        XsdDataContractImporter xsdimp = new XsdDataContractImporter();
        xsdimp.Options = new ImportOptions();
        xsdimp.Options.DataContractSurrogate = new LegacyPersonTypeSurrogate();
        xsdimp.Import(xsdexp.Schemas);

        // Write out the imported schema to a C-Sharp file.
        using (FileStream fs3 = new FileStream("sample.cs", FileMode.Create))
        {
            TextWriter tw = new StreamWriter(fs3);
            CodeDomProvider cdp = new Microsoft.CSharp.CSharpCodeProvider();
            cdp.GenerateCodeFromCompileUnit(xsdimp.CodeCompileUnit, tw, null);
            tw.Flush();
        }

        Console.WriteLine("\n To see the results of schema export and import,");
        Console.WriteLine(" see SAMPLE.XSD and SAMPLE.CS.\n");

        Console.WriteLine(" Press ENTER to terminate the sample.\n");
        Console.ReadLine();
    }
}


// This is the Employee (outer) type used in the sample.
[DataContract()]
class Employee
{
    [DataMember]
    public DateTime date_hired;

    [DataMember]
    public Decimal salary;

    [DataMember]
    public Person person;
}

// This is the Person (inner) type used in the sample.
// Note that it is a legacy XmlSerializable type and not a DataContract type.

public class Person
{
    [XmlElement("FirstName")]
    public string first_name;

    [XmlElement("LastName")]
    public string last_name;

    [XmlAttribute("Age")]
    public int age;

    public Person() { }
}

// This is the surrogated version of the Person type
// that will be used for its serialization/deserialization.
[DataContract]
class PersonSurrogated
{
    [DataMember]
    public string xmlData;
    // xmlData will store the XML returned for a Person instance by the XmlSerializer.
}

// This is the surrogate that substitutes PersonSurrogated for Person.
class LegacyPersonTypeSurrogate : IDataContractSurrogate
{
    public Type GetDataContractType(Type type)
    {
        // "Person" will be serialized as "PersonSurrogated"
        // This method is called during serialization,
        // deserialization, and schema export. 
        if (typeof(Person).IsAssignableFrom(type))
        {
            return typeof(PersonSurrogated);
        }
        return type;
    }
    public object GetObjectToSerialize(object obj, Type targetType)
    {
        // This method is called on serialization.
        // If Person is being initialized...
        if (obj is Person)
        {
            // ... use the XmlSerializer to perform the actual serialization.
            PersonSurrogated ps = new PersonSurrogated();
            XmlSerializer xs = new XmlSerializer(typeof(Person));
            StringWriter sw = new StringWriter();
            xs.Serialize(sw, (Person)obj);
            ps.xmlData = sw.ToString();
            return ps;
        }
        return obj;
    }
    public object GetDeserializedObject(object obj, Type targetType)
    {
        // This method is called on deserialization.
        // If PersonSurrogated is being deserialized...
        if (obj is PersonSurrogated)
        {
            //... use the XmlSerializer to do the actual deserialization.
            PersonSurrogated ps = (PersonSurrogated)obj;
            XmlSerializer xs = new XmlSerializer(typeof(Person));
            return (Person)xs.Deserialize(new StringReader(ps.xmlData));
        }
        return obj;
    }
    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
        // This method is called on schema import.

        // If a PersonSurrogated data contract is in the specified namespace,
        // do not create a new type for it because there is already an existing type, "Person".
        if (typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample"))
        {
            if (typeName.Equals("PersonSurrogated"))
            {
                return typeof(Person);
            }
        }
        return null;
    }

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
    {
        // Not used in this sample.
        // You could use this method to construct an entirely 
        // new CLR type when a certain type is imported, or modify a generated
        // type in some way.
        return typeDeclaration;
    }


    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
        // Not used in this sample
        return null;
    }

    public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
    {
        // Not used in this sample
        return null;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {
        // Not used in this sample
    }
}

Windows 7, Windows Vista, Windows XP SP2, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0
Tags What's this?: Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Processing
© 2009 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement | Site Feedback
Page view tracker