代码改变世界

WCF 第六章 序列化和编码 使用代理序列化类型

2010-12-21 14:37  DanielWise  阅读(797)  评论(1编辑  收藏  举报

有时你可能需要完成一个不可序列化或者需要对序列化内容进行改变的序列化过程。一个例子是由第三方组件提供者提供或者一个你不再拥有源码的组件中的一个类型。下面的例子显示了一个不可序列化的类(查看列表6.26),Employee.这个类故意不生成一个默认构造函数而且它没有任何可写的字段或属性。这意味着它不可使用任何我们到目前为止提到的序列化技术来序列化它。为了序列化这个类我们需要提供一个可以代表序列化类的代理。

列表6.26 不可序列化的Employee类

public class Employee
    {
        private int employeeID;
        private string firstName;
        private string lastName;

        public Employee(int employeeID, string firstName, string lastName)
        {
            this.employeeID = employeeID;
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public int EmployeeID
        {
            get { return employeeID; }
        }

        public string FirstName
        {
            get { return firstName; }
        }

        public string LastName
        {
            get { return lastName; }
        }
    }

  你需要两步来开发一个代理。第一步是定义代表序列化类型的数据契约。第二部是实现一个基于IDataContractSurrogate接口的数据契约代理。我们将要检查三个主要的方法是GetDataContractType, GetDeserializedObject和GetObjectToSerialize方法。GetDataContractType 给DataContractSerializer返回序列化类型,GetDeserializedObject和GetObjectToSerialize按要求执行反序列化和序列化。EmployeeSurrogate类在列表6.27中显示。

列表6.27 Employee代理类

using System.Runtime.Serialization;

namespace Services
{
    [DataContract]
    internal class EmployeeSurrogated
    {
        [DataMember]
        private int employeeID;
        [DataMember]
        private string firstName;
        [DataMember]
        private string lastName;

        public EmployeeSurrogated(int employeeID, string firstName, string lastName)
        {
            this.employeeID = employeeID;
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public int EmployeeID
        {
            get { return employeeID; }
        }

        public string FirstName
        {
            get { return firstName; }
        }

        public string LastName
        {
            get { return lastName; }
        }
    }

    public class EmployeeSurrogate : IDataContractSurrogate
    {
        #region IDataContractSurrogate Members

        public object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            return null; //NotImplement
        }

        public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
        {
            return null; //NotImplement
        }

        public Type GetDataContractType(Type type)
        {
            if (typeof(Employee).IsAssignableFrom(type))
            {
                return typeof(EmployeeSurrogated);
            }
            return type;
        }

        public object GetDeserializedObject(object obj, Type targetType)
        {
            if (obj is EmployeeSurrogated)
            {
                EmployeeSurrogated oldEmployee = (EmployeeSurrogated)obj;
                Employee newEmployee = new Employee(oldEmployee.EmployeeID, oldEmployee.FirstName, oldEmployee.LastName);
                return newEmployee;
            }
            return obj;
        }

        public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
        {
            throw new NotImplementedException();
        }

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            if (obj is Employee)
            {
                Employee oldEmployee = (Employee)obj;
                EmployeeSurrogated newEmployee = new EmployeeSurrogated(oldEmployee.EmployeeID, oldEmployee.FirstName, oldEmployee.LastName);
                return newEmployee;
            }
            return obj;
        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            if (typeNamespace.Equals("http://schemas.datacontract.org/2004/07/EmployeeSurrogated"))
            {
                if (typeName.Equals("EmployeeSurrogated"))
                {
                    return typeof(Employee);
                }
            }
            return null;
        }

        public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
        {
            return typeDeclaration;
        }

        #endregion
    }
}

  我们通过让DataContractSerializer知道代理类来将所有内容放到一起。你需要实例化DataContractSerializer并将EmployeeSurrogated类传递给构造函数,如列表6.28显示。

列表6.28 使用DataContractSerializer的Employee代理类

    class Program
    {
        static void TryToSerialize(Employee e)
        {
            DataContractSerializer dcs = new DataContractSerializer(typeof(Employee));
            using (StringWriter sw = new StringWriter())
            {
                using (XmlWriter xw = XmlWriter.Create(sw))
                {
                    try
                    {
                        dcs.WriteObject(xw, e);
                    }
                    catch(InvalidDataContractException ex)
                    {
                        Console.WriteLine("Cannot serialize without a surrogate! {0}", ex.Message);
                    }
                }
            }
        }

        static string SerializeUsingSurrogate(DataContractSerializer dcs, Employee e)
        {
            using (StringWriter sw = new StringWriter())
            {
                using (XmlWriter xw = XmlWriter.Create(sw))
                {
                    dcs.WriteObject(xw, e);
                    xw.Flush();
                    return sw.ToString();
                }
            }
        }

        static Employee DeserializeUsingSurrogate(DataContractSerializer dcs, string employeeAsString)
        {
            using (StringReader tr = new StringReader(employeeAsString))
            {
                using (XmlReader xr = XmlReader.Create(tr))
                {
                    return dcs.ReadObject(xr) as Employee;
                }
            }
        }

        static void Main(string[] args)
        {
            Employee e = new Employee(12345, "Daniel", "Dong");

            TryToSerialize(e);

            DataContractSerializer dcs = new DataContractSerializer(typeof(Employee), 
                null, int.MaxValue, false, false, new EmployeeSurrogate());

            string employeeAsString = SerializeUsingSurrogate(dcs, e);

            e = DeserializeUsingSurrogate(dcs, employeeAsString);

            Console.ReadLine();
        }
    }