• WCF初探-24:WCF序列化和反序列化


    前言

    • WCF包含很多封装的内部机制,这些是我们在编写程序时不会经常看到的。比如上一篇讲解的Message。这一篇我将讲解WCF的另一种内部机制,WCF的序列化和反序列化。通常我们在编写WCF服务程序的时候,我们并没有手动对WCF的数据传递做序列化和反序列化的操作,这是因为WCF默认通过序列化引擎DataContractSerializer帮我们做了这些操作,使得开发人员只需关注数据对象定义本身(比如数据协定、消息协定),而不必关注数据对象的在WCF传输时的序列化机制。
    • DataContractSerializer 可在 .NET Framework 对象和 XML 之间进行双向转换。在对 .NET Framework 对象进行序列化时,序列化程序了解各种序列化编程模型,包括新的数据协定模型。此序列化程序支持下列类型:
    1. 基元类型(如:整数、字符串和字节数组)以及某些特殊类型(如 XmlElement 和 DateTime),这些特殊类型也被视为基元类型。
    2. 数据协定类型(用 DataContractAttribute 属性标记的类型)。
    3. 用 SerializableAttribute 属性标记的类型,包括实现 ISerializable 接口的类型。
    4. 实现 IXmlSerializable 接口的类型。
    5. 许多常见集合类型,包括许多泛型集合类型。

    使用DataContractSerializer序列化和反序列化

    • 对对象进行序列化最基本的方法是将其传递到 WriteObject 方法。该方法有三个重载,每个重载分别用于写入到 Stream、XmlWriter 或 XmlDictionaryWriter。使用 Stream 重载时,输出是采用 UTF-8 编码的 XML。使用 XmlDictionaryWriter 重载时,序列化程序会针对二进制 XML 优化其输出。参考代码如下:
       User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
        FileStream writer = new FileStream(fileName, FileMode.Create);
        DataContractSerializer ser =new DataContractSerializer(typeof(User));
        ser.WriteObject(writer, user);
        writer.Close();
    • 对对象进行反序列化的最基本的方式是调用 ReadObject 方法重载之一。该方法有三个重载,每个重载分别用于读取 XmlDictionaryReader、XmlReader 或 Stream。请注意,Stream 重载将创建不受任何配额保护的文本 XmlDictionaryReader,此重载仅应用于读取受信任的数据。还请注意,必须将 ReadObject 方法返回的对象强制转换为适当的类型。参考代码如下:
        FileStream fs = new FileStream(fileName,FileMode.Open);
        XmlDictionaryReader reader =XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(User));
        User deserializedUser =(User)ser.ReadObject(reader, true);

    使用DataContractSerializer序列化和反序列化示例如下:

    • 创建一个名称为WcfDataContractSerializer的解决方案,添加一个名称为WcfDataContractSerializer的控制台引用程序。修改Program.cs代码如下:
    复制代码
    using System;
    using System.Runtime.Serialization;
    using System.IO;
    using System.Xml;
    
    namespace WcfDataContractSerializer
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    WriteObject("DataContractSerializerExample.xml");
                    ReadObject("DataContractSerializerExample.xml");
    
                }
    
                catch (SerializationException serExc)
                {
                    Console.WriteLine("序列化失败");
                    Console.WriteLine(serExc.Message);
                }
                catch (Exception exc)
                {
                    Console.WriteLine(
                    "序列化操作失败: {0} StackTrace: {1}",
                    exc.Message, exc.StackTrace);
                }
    
                finally
                {
                    Console.WriteLine("按 <Enter> 键退出....");
                    Console.ReadLine();
                }
            }
    
            public static void WriteObject(string fileName)
            {
                Console.WriteLine("创建User对象并序列化它");
                User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
                FileStream writer = new FileStream(fileName, FileMode.Create);
                DataContractSerializer ser =new DataContractSerializer(typeof(User));
                ser.WriteObject(writer, user);
                writer.Close();
                Console.WriteLine("序列化User对象成功,请到程序Bin目录下查看DataContractSerializerExample.xml文件");
            }
    
            public static void ReadObject(string fileName)
            {
                Console.WriteLine("反序列化实例对象");
                FileStream fs = new FileStream(fileName,FileMode.Open);
                XmlDictionaryReader reader =XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
                DataContractSerializer ser = new DataContractSerializer(typeof(User));
                User deserializedUser =(User)ser.ReadObject(reader, true);
                reader.Close();
                fs.Close();
                Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "ID", "Name", "Age", "Nationality");
                Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}",
                      deserializedUser.ID.ToString(),
                      deserializedUser.Name.ToString(),
                      deserializedUser.Age.ToString(),
                      deserializedUser.Nationality.ToString());
            }
        }
    
        [DataContract]
        public class User
        {
            [DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
            [DataMember]
            public string Nationality { get; set; }
        }
    }
    复制代码
    • 运行程序结果如下:

      

      打开程序Bin目录下的DataContractSerializerExample.xml,显示结果如下:

      

    使用DataContractJsonSerializer序列化和反序列化

    • 使用DataContractJsonSerializer可以将对象转化为Json格式,如果你习惯使用Json,那么可以使用该序列化引擎作为对象的传输时的序列化工具。该序列化引擎和DataContractSerializer一样,具有WriteObject和ReadObject方法,具体用法参照示例。
    • 注意:该序列化引擎只会对WCF的消息正文进行Json序列化操作,也就是说总个消息还是基于SOAP的XML格式,只有Body部分变成了JSON字符串。

    使用DataContractJsonSerializer序列化和反序列化示例

    • 在先前的解决方案上添加名称为WcfDataContractJsonSerializer的控制台应用程序,修改Program.cs的代码如下:
    复制代码
    using System;
    using System.Runtime.Serialization;
    using System.IO;
    using System.Runtime.Serialization.Json;
    using System.Text;
    
    namespace WcfDataContractJsonSerializer
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("创建User对象并序列化它");
                    User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
                    string jsonString = Serialize<User>(user);
                    Console.WriteLine(jsonString);
    
                    Console.WriteLine("反序列化实例对象");
                    User deserializedUser = Deserialize<User>(jsonString);
                    Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}", "ID", "Name", "Age", "Nationality");
                    Console.WriteLine("{0,-10}{1,-10}{2,-10}{3,-10}",
                          deserializedUser.ID.ToString(),
                          deserializedUser.Name.ToString(),
                          deserializedUser.Age.ToString(),
                          deserializedUser.Nationality.ToString());
                }
    
                catch (SerializationException serExc)
                {
                    Console.WriteLine("序列化失败");
                    Console.WriteLine(serExc.Message);
                }
                catch (Exception exc)
                {
                    Console.WriteLine(
                    "序列化操作失败: {0} StackTrace: {1}",
                    exc.Message, exc.StackTrace);
                }
    
                finally
                {
                    Console.WriteLine("按 <Enter> 键退出....");
                    Console.ReadLine();
                }
            }
    
            public static string Serialize<T>(T item)
            {
                if (item == null) return string.Empty;
                var serializer = new DataContractJsonSerializer(item.GetType());
                using (var ms = new MemoryStream())
                {
                    serializer.WriteObject(ms, item);
                    var sb = new StringBuilder();
                    sb.Append(Encoding.UTF8.GetString(ms.ToArray()));
                    return sb.ToString();
                }
            }
    
            public static T Deserialize<T>(string jsonString)
            {
                if (string.IsNullOrEmpty(jsonString)) return default(T);
                var ser = new DataContractJsonSerializer(typeof(T));
                using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
                {
                    T jsonObject = (T)ser.ReadObject(ms);
                    return jsonObject;
                }
            }
        }
    
        [DataContract]
        public class User
        {
            [DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
            [DataMember]
            public string Nationality { get; set; }
        }
    }
    复制代码
    • 运行结果如下:

      

    序列化格式大小对比

    • 序列化格式的三种类型:XML文本类型、Json文本类型、二进制类型。接下来,我们通过一个小示例来看看这三种类型序列化时的字节大小。因为我们知道在网络数据传输时,字节大小的传递显得尤为重要呢。
    • 在先前的解决方案中添加名称为WcfSerializerCompare的控制台应用程序,修改Program.cs的代码如下:
    复制代码
    using System;
    using System.Runtime.Serialization;
    using System.IO;
    using System.Runtime.Serialization.Json;
    using System.Xml;
    
    namespace WcfSerializerCompare
    {
        class Program
        {
            static void Main(string[] args)
            {
                MemoryStream stream1 = new MemoryStream();
                MemoryStream stream2 = new MemoryStream();
                MemoryStream stream3 = new MemoryStream();
                User user = new User { ID = 1, Name = "JACK", Age = 20, Nationality = "CHINA" };
    
                DataContractSerializer xmlSerializer = new DataContractSerializer(typeof(User));
                xmlSerializer.WriteObject(stream1, user);
    
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(User));
                jsonSerializer.WriteObject(stream2, user);
    
                DataContractSerializer binarySerializer = new DataContractSerializer(typeof(User));
                XmlDictionaryWriter write = XmlDictionaryWriter.CreateBinaryWriter(stream3);
                binarySerializer.WriteObject(write, user);
                write.Flush();
         
                Console.WriteLine("XML文本字节数大小为:{0}bytes", stream1.Length);
                Console.WriteLine("JSON文本字节数大小为:{0}bytes", stream2.Length);
                Console.WriteLine("二进制字节数大小为:{0}bytes", stream3.Length);
    
                Console.Read();
    
            }
        }
    
        [DataContract]
        public class User
        {
            [DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
            [DataMember]
            public string Nationality { get; set; }
        }
    }
    复制代码
    • 运行结果如下:

      

      从上面的示例可以看出,采用Json文本传输的格式为最小,只有53个字节数。

  • 相关阅读:
    requests+lxml+xpath爬取豆瓣电影
    hisi出的H264码流结构
    单片机复位电路原理介绍
    二极管与、或门,三极管非门电路原理
    Windows Route 路由表命令整理
    理解Windows中的路由表和默认网关
    Windows路由表详解
    linux 路由表设置 之 route 指令详解
    linux中service *** start与直接运行/usr/bin/***的区别
    Linux运行与控制后台进程的方法:nohup, setsid, &, disown, screen
  • 原文地址:https://www.cnblogs.com/linybo/p/13306409.html
Copyright © 2020-2023  润新知