Example 3-1. The DataContractSerializer
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Xml; namespace WCFServiceProgramming { public abstract class XmlObjectSerializer { public virtual object ReadObject(Stream stream); public virtual object ReadObject(XmlReader reader); public virtual void WriteObject(XmlWriter writer, object graph); public void WriteObject(Stream stream, object graph); } public sealed class DataContractSerializer : XmlObjectSerializer { public DataContractSerializer(Type type); //More members } }
Example 3-2. The generic DataContractSerializer<T>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Xml; namespace WCFServiceProgramming { public abstract class XmlObjectSerializer { public virtual object ReadObject(Stream stream); public virtual object ReadObject(XmlReader reader); public virtual void WriteObject(XmlWriter writer, object graph); public void WriteObject(Stream stream, object graph); } public sealed class DataContractSerializer : XmlObjectSerializer { public DataContractSerializer(Type type); //More members } public class DataContractSerializer<T> : XmlObjectSerializer { DataContractSerializer m_DataContractSerializer; public DataContractSerializer() { m_DataContractSerializer = new DataContractSerializer(typeof(T)); } public new T ReadObject(Stream stream) { return (T)m_DataContractSerializer.ReadObject(stream); } public new T ReadObject(XmlReader reader) { return (T)m_DataContractSerializer.ReadObject(reader); } public void WriteObject(Stream stream, T graph) { m_DataContractSerializer.WriteObject(stream, graph); } public void WriteObject(XmlWriter writer, T graph) { m_DataContractSerializer.WriteObject(writer, graph); } //More members } }
Example 3-3. A composite data contract
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace WCFServiceProgramming { [DataContract] struct Address { [DataMember] public string Street; [DataMember] public string City; [DataMember] public string State; [DataMember] public string Zip; } [DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; [DataMember] public Address Address; } }
Example 3-4. Applying the serialization event attributes
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace WCFServiceProgramming { [DataContract] class MyDataContract { [OnSerializing] void OnSerializing(StreamingContext context) { } [OnSerialized] void OnSerialized(StreamingContext context) { } [OnDeserializing] void OnDeserializing(StreamingContext context) { } [OnDeserialized] void OnDeserialized(StreamingContext context) { } //Data members } }
Example 3-5. Initializing nonserializable resources using the deserialized event
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.Data; using System.Data.SqlClient; namespace WCFServiceProgramming { [DataContract] class MyDataContract { IDbConnection m_Connection; [OnDeserialized] void OnDeserialized(StreamingContext context) { m_Connection = new SqlConnection(); } /* Data members */ } }
Example 3-6. Known types in config file
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.runtime.serialization> <dataContractSerializer> <declaredTypes> <add type="Contact,Host,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"> <knownType type="Customer,MyClassLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/> </add> </declaredTypes> </dataContractSerializer> </system.runtime.serialization> </configuration>
Example 3-7. Missing members are initialized to their default value(Server Side)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.ServiceModel; using System.Diagnostics; namespace WCFServiceProgramming { /////////////////////////// Service Side ////////////////////////////// [DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; [DataMember] public string Address; } [ServiceContract] interface IContactManager { [OperationContract] void AddContact(Contact contact); //... } class ContactManager : IContactManager { public void AddContact(Contact contact) { Trace.WriteLine("First name = " + contact.FirstName); Trace.WriteLine("Last name = " + contact.LastName); Trace.WriteLine("Address = " + (contact.Address ?? "Missing")); //... } //... } }
Example 3-7. Missing members are initialized to their default value(Client Side)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Channels; using System.ServiceModel; using System.Runtime.Serialization; namespace WCFServiceProgramming { /////////////////////////// Client Side ////////////////////////////// [DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } class ContactManagerClient : ClientBase<IContactManager>, IContactManager { public void AddContact(Contact contact) { Channel.AddContact(contact); } } class Program { static void Main(string[] args) { Contact contact = new Contact(); contact.FirstName = "Juval"; contact.LastName = "Lowy"; ContactManagerClient proxy = new ContactManagerClient(); proxy.AddContact(contact); proxy.Close(); } } }
Example 3-8. Implementing IExtensibleDataObject
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace WCFServiceProgramming { [DataContract] class Contact : IExtensibleDataObject { ExtensionDataObject m_ExtensionData; public ExtensionDataObject ExtensionData { get { return m_ExtensionData; } set { m_ExtensionData = value; } } [DataMember] public string FirstName; [DataMember] public string LastName; } }
Example 3-9. Using an enum in a data contract
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; namespace WCFServiceProgramming { enum ContactType { Customer, Vendor, Partner } [DataContract] class Contact { [DataMember] public ContactType ContactType; [DataMember] public string FirstName; [DataMember] public string LastName; } }
Example 3-10. Type-safe data set and data table
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Collections; using System.ComponentModel; namespace WCFServiceProgramming.Library { [Serializable] public partial class MyDataSet : DataSet { [Serializable] public partial class ContactsDataTable : DataTable, IEnumerable { public void AddContactsRow(ContactsRow row); public ContactsRow AddContactsRow(string firstName, string lastName); public IEnumerator GetEnumerator() { throw new NotImplementedException(); } } public partial class ContactsRow : DataRow { public string FirstName { get; set; } public string LastName { get; set; } // More members } } public partial class ContactsTableAdapter : Component { public virtual MyDataSet.ContactsDataTable GetData(); // More members } }
Example 3-11. Using DataTableHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization; using System.ServiceModel; namespace WCFServiceProgramming.Library { [DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } [ServiceContract] interface IContactManager { [OperationContract] Contact[] GetContacts( ); //... } class ContactManager : IContactManager { public Contact[] GetContacts() { ContactsTableAdapter adapter = new ContactsTableAdapter(); MyDataSet.ContactsDataTable contactsTable = adapter.GetData(); Converter<MyDataSet.ContactsRow, Contact> converter; converter = delegate(MyDataSet.ContactsRow row) { Contact contact = new Contact(); contact.FirstName = row.FirstName; contact.LastName = row.LastName; return contact; }; return DataTableHelper.ToArray(contactsTable, converter); } // Rest of the implementation } }
Example 3-12. The DataTableHelper class
using System; using System.Collections; using System.Linq; using System.Text; using System.Data; using System.Diagnostics; using System.Runtime.Serialization; namespace WCFServiceProgramming.Library { public static class DataTableHelper { public static T[] ToArray<R, T>(DataTable table, Converter<R, T> converter) where R : DataRow { if (table.Rows.Count == 0) { return new T[] { }; } // Verify [DataContract] or [Serializable] on T Debug.Assert(IsDataContract(typeof(T)) || typeof(T).IsSerializable); // Verify table contains correct rows Debug.Assert(MatchingTableRow<R>(table)); return System.Collections.UnsafeToArray(table.Rows, converter); } private static bool IsDataContract(Type type) { object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false); return attributes.Length == 1; } private static bool MatchingTableRow<R>(DataTable table) { if (table.Rows.Count == 0) { return true; } return table.Rows[0] is R; } } }
Example 3-13. Using bounded generic types
Example 3-14. Marshaling a list as an array
Example 3-15. Marshaling a custom collection as an array