前言

  • 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 = , Name = "JACK", Age = , 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 = , Name = "JACK", Age = , 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 = , Name = "JACK", Age = , 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 = , Name = "JACK", Age = , 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个字节数。

WCF初探-24:WCF序列化和反序列化的更多相关文章

  1. WCF初探文章列表

    WCF初探-1:认识WCF WCF初探-6:WCF服务配置 WCF初探-2:手动实现WCF程序 WCF初探-7:WCF服务配置工具使用 WCF初探-3:WCF消息交换模式之单向模式 WCF初探-8:W ...

  2. 对 JSON 数据进行序列化和反序列化

    如何:对 JSON 数据进行序列化和反序列化 2017/03/30 作者 JSON(JavaScript 对象符号)是一种高效的数据编码格式,可用于在客户端浏览器和支持 AJAX 的 Web 服务之间 ...

  3. 序列化和反序列化,异步调用web/wcf/函数

    //xml序列化 public static string Seria(DataSet ds) { XmlSerializer serializer = new XmlSerializer(typeo ...

  4. WCF序列化与反序列化问题

    转自:http://www.cnblogs.com/wangweimutou/p/4505447.html WCF包含很多封装的内部机制,这些是我们在编写程序时不会经常看到的.比如上一篇讲解的Mess ...

  5. WCF初探-20:WCF错误协定

    WCF错误协定概述 在所有托管应用程序中,处理错误由 Exception 对象表示. 在基于 SOAP 的应用程序(如 WCF 应用程序)中,服务方法使用 SOAP 错误消息来传递处理错误信息. SO ...

  6. WCF初探-25:WCF中使用XmlSerializer类

    前言 在上一篇WCF序列化和反序列化中,文章介绍了WCF序列化和反序列化的机制,虽然WCF针对序列化提供了默认的DataContractSerializer序列化引擎,但是WCF还支持其他的序列化引擎 ...

  7. WCF初探-16:WCF数据协定之基础知识

    数据协定概念 “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每一个做数 ...

  8. WCF初探-22:WCF中使用Message类(上)

    前言 从我们学习WCF以来,就一直强调WCF是基于消息的通信机制.但是由于WCF给我们做了高级封装,以至于我们在使用WCF的时候很少了解到消息的内部机制.由于WCF的架构的可扩展性,针对一些特殊情况, ...

  9. 跟我一起学WCF(7)——WCF数据契约与序列化详解

    一.引言 在前面博文介绍到,WCF的契约包括操作契约.数据契约.消息契约和错误契约,前面一篇博文已经结束了操作契约的介绍,接下来自然就是介绍数据契约了.所以本文要分享的内容就是数据契约. 二.数据契约 ...

随机推荐

  1. input内强制保留小数点后两位 位数不足时自动补0

    input内强制保留小数点后两位 位数不足时自动补0 小数点后位数超出2位时进行四舍五入 需引入jquery包 1.11.2版本 1 function xiaoshu(x) 2 { 3 var f = ...

  2. 解决ADB端口占用问题

    方式一5037为adb默认端口,若5037端口被占用,查看占用端口的进程PIDC:\Users\wwx229495>netstat -aon|findstr 5037   TCP    127. ...

  3. Effective_Python mapreduce

    完全吊炸天构造器的写法... import os import threading,time class GenericInputData(object): def read(self): raise ...

  4. myisam压缩(前缀压缩)索引

    myisam使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,默认只压缩字符串,但通过参数配置也可以对整数做压缩,myisam压缩每个索引块的方法是,先完全保存索引块中的第一个值,然后将其 ...

  5. YTU 2345: 后序遍历二叉树

    原文链接:https://www.dreamwings.cn/ytu2345/2611.html 2345: 后序遍历二叉树 时间限制: 1 Sec  内存限制: 128 MB 提交: 3  解决:  ...

  6. js相关总结

    1.都是gbk格式的页面使用ajax请求,发起前改变编码格式,可避免乱码. $.ajaxSetup({     'beforeSend' : function(xhr) {         xhr.o ...

  7. js瀑布流

    <!doctype html><html><head><meta charset="utf-8"><title>无标题文 ...

  8. fidder 使用教程

    fidder 使用教程 1. Fiddler 是什么? Fiddler是用C#编写的一个免费的HTTP/HTTPS网络调试器.英语中Fiddler是小提琴的意思,Fiddler Web Debugge ...

  9. 关于autoptr

    参考自: http://www.cppblog.com/expter/archive/2009/03/29/78270.html auto_ptr是什么. 解释1.auto_ptr是一个管理指针的对象 ...

  10. Deep Learning 7_深度学习UFLDL教程:Self-Taught Learning_Exercise(斯坦福大学深度学习教程)

    前言 理论知识:自我学习 练习环境:win7, matlab2015b,16G内存,2T硬盘 练习内容及步骤:Exercise:Self-Taught Learning.具体如下: 一是用29404个 ...